Moved code from LocalRepo to the Swap UI to reuse it.

Along with a bunch of networking stuff, a lot of UI to do with selecting
apps to swap was also moved. The background on the list is transparent,
which allows blue to shine through. Also, the text on the list items is
white, which will not work with a white background.

I've temporarily dropped support for searching this list too, until
I get some feedback from carrie et al.

NOTE: This stuff was written before hans fixed apcompat problems with
LocalRepoActivity, but then rebased over it later. As such, it doesn't
contain his fixes. Will need to do that before a stable release. i.e.
Still has a bit of a dependency on API 11 which needs to be resolved.
This commit is contained in:
Peter Serwylo 2014-06-20 21:44:42 +09:30
parent ae9cb5b89b
commit 6d807793c2
14 changed files with 464 additions and 43 deletions

View File

@ -14,7 +14,7 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<Button <Button
android:id="@+id/checkbox_dont_show" android:id="@+id/button_start_swap"
android:text="START A SWAP" android:text="START A SWAP"
style="@style/SwapTheme.AppList.StartButton" style="@style/SwapTheme.AppList.StartButton"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -14,27 +14,27 @@
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
tools:text="One person needs to scan the code, or type the URL of the other swapper into a browser." android:text="One person needs to scan the code, or type the URL of the other swapper into a browser."
style="@style/SwapTheme.Wizard.MainText"/> style="@style/SwapTheme.Wizard.MainText"/>
<ImageView <ImageView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/wifi_qr_code" android:id="@+id/wifi_qr_code"
tools:src="@drawable/swap_qr_example" tools:src="@drawable/swap_qr_example"
android:layout_below="@+id/textView" android:layout_above="@+id/device_ip_address"/> android:layout_below="@+id/textView"
android:layout_above="@+id/device_ip_address"/>
<Button style="@style/SwapTheme.Wizard.OptionButton" <Button style="@style/SwapTheme.Wizard.OptionButton"
android:id="@+id/btn_not_working" android:id="@+id/btn_not_working"
android:text="It's not working" android:text="@string/swap_wifi_qr_not_working"
android:layout_alignParentBottom="true" /> android:layout_alignParentBottom="true" />
<Button style="@style/SwapTheme.Wizard.OptionButton" <Button style="@style/SwapTheme.Wizard.OptionButton"
android:text="Open QR Code Scanner" android:text="@string/open_qr_code_scanner"
android:layout_above="@id/btn_not_working" android:layout_gravity="center" android:id="@+id/button"/> android:layout_above="@id/btn_not_working" android:layout_gravity="center" android:id="@+id/button"/>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/device_ip_address" android:id="@+id/device_ip_address"
tools:text="192.168.1.1:8888" tools:text="192.168.1.1:8888"
android:layout_above="@+id/button" android:layout_centerHorizontal="true" android:layout_above="@+id/button" android:layout_centerHorizontal="true"

11
res/menu/swap_skip.xml Normal file
View File

@ -0,0 +1,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_skip"
android:title="Skip"
android:titleCondensed="Skip"/>
<!-- Currently in a style, but that style probably wont work on 8 -> 11 devices -->
<!--android:drawable="@drawable/swap_action_button_skin"-->
</menu>

View File

@ -303,4 +303,6 @@
<string name="swap">Swap apps</string> <string name="swap">Swap apps</string>
<string name="swap_no_wifi_network">No network yet</string> <string name="swap_no_wifi_network">No network yet</string>
<string name="swap_view_available_networks">(Tap to open available networks)</string> <string name="swap_view_available_networks">(Tap to open available networks)</string>
<string name="swap_wifi_qr_not_working">It\'s not working</string>
<string name="open_qr_code_scanner">Open QR Code Scanner</string>
</resources> </resources>

View File

@ -40,6 +40,8 @@
</style> </style>
<style name="SwapTheme.AppList" parent="AppThemeLightWithDarkActionBar"> <style name="SwapTheme.AppList" parent="AppThemeLightWithDarkActionBar">
<item name="android:windowBackground">@color/white</item>
<item name="android:background">@color/white</item>
</style> </style>
<style name="SwapTheme.AppList.StartButton"> <style name="SwapTheme.AppList.StartButton">

View File

@ -56,6 +56,7 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi
public static final String PREF_ENABLE_PROXY = "enableProxy"; public static final String PREF_ENABLE_PROXY = "enableProxy";
public static final String PREF_PROXY_HOST = "proxyHost"; public static final String PREF_PROXY_HOST = "proxyHost";
public static final String PREF_PROXY_PORT = "proxyPort"; public static final String PREF_PROXY_PORT = "proxyPort";
public static final String PREF_SHOW_NFC_DURING_SWAP = "showNfcDuringSwap";
private static final boolean DEFAULT_COMPACT_LAYOUT = false; private static final boolean DEFAULT_COMPACT_LAYOUT = false;
private static final boolean DEFAULT_ROOTED = true; private static final boolean DEFAULT_ROOTED = true;
@ -70,6 +71,7 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi
private static final boolean DEFAULT_ENABLE_PROXY = false; private static final boolean DEFAULT_ENABLE_PROXY = false;
public static final String DEFAULT_PROXY_HOST = "127.0.0.1"; public static final String DEFAULT_PROXY_HOST = "127.0.0.1";
public static final int DEFAULT_PROXY_PORT = 8118; public static final int DEFAULT_PROXY_PORT = 8118;
public static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true;
private boolean compactLayout = DEFAULT_COMPACT_LAYOUT; private boolean compactLayout = DEFAULT_COMPACT_LAYOUT;
private boolean filterAppsRequiringRoot = DEFAULT_ROOTED; private boolean filterAppsRequiringRoot = DEFAULT_ROOTED;
@ -115,6 +117,14 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi
return preferences.getBoolean(PREF_PERMISSIONS, DEFAULT_PERMISSIONS); return preferences.getBoolean(PREF_PERMISSIONS, DEFAULT_PERMISSIONS);
} }
public boolean showNfcDuringSwap() {
return preferences.getBoolean(PREF_SHOW_NFC_DURING_SWAP, DEFAULT_SHOW_NFC_DURING_SWAP);
}
public void setShowNfcDuringSwap(boolean show) {
preferences.edit().putBoolean(PREF_SHOW_NFC_DURING_SWAP, show).commit();
}
public boolean expertMode() { public boolean expertMode() {
return preferences.getBoolean(PREF_EXPERT, DEFAULT_EXPERT); return preferences.getBoolean(PREF_EXPERT, DEFAULT_EXPERT);
} }

View File

@ -5,6 +5,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
@ -13,7 +14,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
@ -33,7 +33,7 @@ public class JoinWifiFragment extends Fragment {
joinWifiView.setOnClickListener(new View.OnClickListener() { joinWifiView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Toast.makeText(getActivity(), "Touched view", Toast.LENGTH_LONG); openAvailableNetworks();
} }
}); });
return joinWifiView; return joinWifiView;
@ -61,4 +61,8 @@ public class JoinWifiFragment extends Fragment {
ssidView.setText(text); ssidView.setText(text);
} }
} }
private void openAvailableNetworks() {
startActivity(new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK));
}
} }

View File

@ -1,17 +1,61 @@
package org.fdroid.fdroid.views.swap; package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.content.Context;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
public class NfcSwapFragment extends Fragment { public class NfcSwapFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.swap_nfc, container, false); View view = inflater.inflate(R.layout.swap_nfc, container, false);
CheckBox dontShowAgain = (CheckBox)view.findViewById(R.id.checkbox_dont_show);
dontShowAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Preferences.get().setShowNfcDuringSwap(!isChecked);
}
});
setupNfc();
return view;
}
public static boolean isNfcSupported(Context context) {
return Build.VERSION.SDK_INT >= 14 && getNfcAdapter(context) != null;
}
@TargetApi(10)
private static NfcAdapter getNfcAdapter(Context context) {
return NfcAdapter.getDefaultAdapter(context.getApplicationContext());
}
@TargetApi(10)
private void setupNfc() {
// the required NFC API was added in 4.0 aka Ice Cream Sandwich
if (Build.VERSION.SDK_INT >= 14) {
NfcAdapter nfcAdapter = getNfcAdapter(getActivity());
if (nfcAdapter == null)
return;
nfcAdapter.setNdefPushMessage(new NdefMessage(new NdefRecord[] {
NdefRecord.createUri(Utils.getSharingUri(getActivity(), FDroidApp.repo)),
}), getActivity());
}
} }
} }

View File

@ -0,0 +1,198 @@
package org.fdroid.fdroid.views.swap;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import java.util.HashSet;
public class SelectAppsFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor>, SearchView.OnQueryTextListener {
private PackageManager packageManager;
private Drawable defaultAppIcon;
private ActionMode mActionMode = null;
private String mCurrentFilterString;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LayoutInflater themedInflater = (LayoutInflater)new ContextThemeWrapper(inflater.getContext(), R.style.SwapTheme_AppList).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = super.onCreateView(themedInflater, container, savedInstanceState);
ListView listView = (ListView)view.findViewById(android.R.id.list);
listView.addHeaderView(themedInflater.inflate(R.layout.swap_create_header, null, false));
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText(getString(R.string.no_applications_found));
packageManager = getActivity().getPackageManager();
defaultAppIcon = getResources().getDrawable(android.R.drawable.sym_def_app_icon);
ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(),
R.layout.select_local_apps_list_item,
null,
new String[] {
InstalledAppProvider.DataColumns.APPLICATION_LABEL,
InstalledAppProvider.DataColumns.APP_ID,
},
new int[] {
R.id.application_label,
R.id.package_name,
});
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (columnIndex == cursor.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)) {
String packageName = cursor.getString(columnIndex);
TextView textView = (TextView) view.findViewById(R.id.package_name);
textView.setText(packageName);
LinearLayout ll = (LinearLayout) view.getParent().getParent();
ImageView iconView = (ImageView) ll.getChildAt(0);
Drawable icon;
try {
icon = packageManager.getApplicationIcon(packageName);
} catch (PackageManager.NameNotFoundException e) {
icon = defaultAppIcon;
}
iconView.setImageDrawable(icon);
return true;
}
return false;
}
});
setListAdapter(adapter);
setListShown(false); // start out with a progress indicator
// either reconnect with an existing loader or start a new one
getLoaderManager().initLoader(0, null, this);
// build list of existing apps from what is on the file system
if (FDroidApp.selectedApps == null) {
FDroidApp.selectedApps = new HashSet<String>();
for (String filename : LocalRepoManager.get(getActivity()).repoDir.list()) {
if (filename.matches(".*\\.apk")) {
String packageName = filename.substring(0, filename.indexOf("_"));
FDroidApp.selectedApps.add(packageName);
}
}
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cursor c = (Cursor) l.getAdapter().getItem(position);
String packageName = c.getString(c.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID));
if (FDroidApp.selectedApps.contains(packageName)) {
FDroidApp.selectedApps.remove(packageName);
} else {
FDroidApp.selectedApps.add(packageName);
}
}
@Override
public CursorLoader onCreateLoader(int id, Bundle args) {
Uri baseUri;
if (TextUtils.isEmpty(mCurrentFilterString)) {
baseUri = InstalledAppProvider.getContentUri();
} else {
baseUri = InstalledAppProvider.getSearchUri(mCurrentFilterString);
}
return new CursorLoader(
this.getActivity(),
baseUri,
InstalledAppProvider.DataColumns.ALL,
null,
null,
InstalledAppProvider.DataColumns.APPLICATION_LABEL);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
((SimpleCursorAdapter) this.getListAdapter()).swapCursor(cursor);
ListView listView = getListView();
String fdroid = loader.getContext().getPackageName();
for (int i = 0; i < listView.getCount() - 1; i++) {
Cursor c = ((Cursor) listView.getItemAtPosition(i + 1));
String packageName = c.getString(c.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID));
if (TextUtils.equals(packageName, fdroid)) {
listView.setItemChecked(i, true); // always include FDroid
} else {
for (String selected : FDroidApp.selectedApps) {
if (TextUtils.equals(packageName, selected)) {
listView.setItemChecked(i, true);
}
}
}
}
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter) this.getListAdapter()).swapCursor(null);
}
@Override
public boolean onQueryTextChange(String newText) {
String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
if (mCurrentFilterString == null && newFilter == null) {
return true;
}
if (mCurrentFilterString != null && mCurrentFilterString.equals(newFilter)) {
return true;
}
mCurrentFilterString = newFilter;
getLoaderManager().restartLoader(0, null, this);
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
// this is not needed since we respond to every change in text
return true;
}
public String getCurrentFilterString() {
return mCurrentFilterString;
}
}

View File

@ -0,0 +1,38 @@
package org.fdroid.fdroid.views.swap;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.fdroid.fdroid.R;
public class StartSwapFragment extends Fragment {
private SwapProcessManager manager;
public void onAttach(Activity activity) {
super.onAttach(activity);
manager = (SwapProcessManager)activity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LayoutInflater themedInflater = (LayoutInflater)new ContextThemeWrapper(inflater.getContext(), R.style.SwapTheme_AppList).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = themedInflater.inflate(R.layout.swap_blank, container, false);
view.findViewById(R.id.button_start_swap).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
manager.nextStep();
}
});
return view;
}
}

View File

@ -6,41 +6,32 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.fragments.SelectLocalAppsFragment;
public class SwapActivity extends ActionBarActivity implements SwapProcessManager { public class SwapActivity extends ActionBarActivity implements SwapProcessManager {
private static final String STATE_START_SWAP = "startSwap";
private static final String STATE_SELECT_APPS = "selectApps";
private static final String STATE_JOIN_WIFI = "joinWifi"; private static final String STATE_JOIN_WIFI = "joinWifi";
private static final String STATE_NFC = "nfc"; private static final String STATE_NFC = "nfc";
private static final String STATE_WIFI_QR = "wifiQr"; private static final String STATE_WIFI_QR = "wifiQr";
@Override private MenuItem nextMenuItem;
public boolean onCreateOptionsMenu(Menu menu) { private String nextMenuItemLabel;
getMenuInflater().inflate(R.menu.swap, menu);
MenuItem next = menu.getItem(0);
MenuItemCompat.setShowAsAction(next, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
@Override public void nextStep() {
public boolean onPrepareOptionsMenu(Menu menu) {
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_next) {
moveToNext();
return true;
}
return super.onOptionsItemSelected(item);
}
private void moveToNext() {
getSupportFragmentManager().popBackStack(); getSupportFragmentManager().popBackStack();
FragmentManager.BackStackEntry lastFragment = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1); FragmentManager.BackStackEntry lastFragment = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1);
String name = lastFragment.getName(); String name = lastFragment.getName();
switch (name) { switch (name) {
case STATE_START_SWAP:
onSelectApps();
break;
case STATE_SELECT_APPS:
onJoinWifi();
break;
case STATE_JOIN_WIFI: case STATE_JOIN_WIFI:
onAttemptNfc(); onAttemptNfc();
break; break;
@ -51,6 +42,47 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
break; break;
} }
supportInvalidateOptionsMenu();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.swap_next, menu);
nextMenuItem = menu.getItem(0);
nextMenuItem.setVisible(false);
MenuItemCompat.setShowAsAction(nextMenuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
private void hideNextButton() {
nextMenuItemLabel = null;
supportInvalidateOptionsMenu();
}
private void showNextButton() {
nextMenuItemLabel = getString(R.string.next);
supportInvalidateOptionsMenu();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (nextMenuItemLabel == null) {
nextMenuItem.setVisible(false);
return false;
} else {
nextMenuItem.setVisible(true);
nextMenuItem.setTitle(nextMenuItemLabel);
return true;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == nextMenuItem.getItemId()) {
nextStep();
}
return super.onOptionsItemSelected(item);
} }
@Override @Override
@ -62,35 +94,61 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.add(android.R.id.content, new JoinWifiFragment(), STATE_JOIN_WIFI) .add(android.R.id.content, new StartSwapFragment(), STATE_START_SWAP)
.addToBackStack(STATE_JOIN_WIFI) .addToBackStack(STATE_START_SWAP)
.commit(); .commit();
hideNextButton();
} }
} }
@Override private void onSelectApps() {
public void onAttemptNfc() {
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.addToBackStack(STATE_NFC) .add(android.R.id.content, new SelectAppsFragment(), STATE_SELECT_APPS)
.replace(android.R.id.content, new NfcSwapFragment(), STATE_NFC) .addToBackStack(STATE_SELECT_APPS)
.commit(); .commit();
showNextButton();
}
private void onJoinWifi() {
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, new JoinWifiFragment(), STATE_JOIN_WIFI)
.addToBackStack(STATE_JOIN_WIFI)
.commit();
showNextButton();
}
public void onAttemptNfc() {
if (Preferences.get().showNfcDuringSwap() && NfcSwapFragment.isNfcSupported(this)) {
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(STATE_NFC)
.replace(android.R.id.content, new NfcSwapFragment(), STATE_NFC)
.commit();
showNextButton();
} else {
onWifiQr();
}
} }
@Override
public void onBluetooth() { public void onBluetooth() {
} }
@Override
public void onWifiQr() { public void onWifiQr() {
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.addToBackStack(STATE_WIFI_QR) .addToBackStack(STATE_WIFI_QR)
.replace(android.R.id.content, new WifiQrFragment(), STATE_WIFI_QR) .replace(android.R.id.content, new WifiQrFragment(), STATE_WIFI_QR)
.commit(); .commit();
showNextButton();
} }
} }

View File

@ -1,7 +1,5 @@
package org.fdroid.fdroid.views.swap; package org.fdroid.fdroid.views.swap;
public interface SwapProcessManager { public interface SwapProcessManager {
public void onAttemptNfc(); public void nextStep();
public void onBluetooth();
public void onWifiQr();
} }

View File

@ -1,17 +1,73 @@
package org.fdroid.fdroid.views.swap; package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.graphics.LightingColorFilter;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.QrGenAsyncTask;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import java.util.Locale;
public class WifiQrFragment extends Fragment { public class WifiQrFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.swap_nfc, container, false); View view = inflater.inflate(R.layout.swap_wifi_qr, container, false);
ImageView qrImage = (ImageView)view.findViewById(R.id.wifi_qr_code);
// Replace all blacks with the background blue.
qrImage.setColorFilter(new LightingColorFilter(0xffffffff, getResources().getColor(R.color.swap_blue)));
return view;
}
public void onResume() {
super.onResume();
setUIFromWifi();
}
@TargetApi(14)
private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address))
return;
// the fingerprint is not useful on the button label
String buttonLabel = FDroidApp.ipAddressString + ":" + FDroidApp.port;
TextView ipAddressView = (TextView) getView().findViewById(R.id.device_ip_address);
ipAddressView.setText(buttonLabel);
/*
* Set URL to UPPER for compact QR Code, FDroid will translate it back.
* Remove the SSID from the query string since SSIDs are case-sensitive.
* Instead the receiver will have to rely on the BSSID to find the right
* wifi AP to join. Lots of QR Scanners are buggy and do not respect
* custom URI schemes, so we have to use http:// or https:// :-(
*/
final String qrUriString = Utils.getSharingUri(getActivity(), FDroidApp.repo).toString()
.replaceFirst("fdroidrepo", "http")
.replaceAll("ssid=[^?]*", "")
.toUpperCase(Locale.ENGLISH);
Log.i("QRURI", qrUriString);
// zxing requires >= 8
// TODO: What about 7? I don't feel comfortable bumping the min version for this...
// I would suggest show some alternate info, with directions for how to add a new repository manually.
if (Build.VERSION.SDK_INT >= 8)
new QrGenAsyncTask(getActivity(), R.id.wifi_qr_code).execute(qrUriString);
} }
} }