WIP: Hooking up specific peers from the "nearby peers".

Touching the peers will prompt app selection for swap, then skip the
wifi and NFC screens, then show updating info, then a list of apps to
swap.
This commit is contained in:
Peter Serwylo 2015-06-26 00:13:52 +10:00
parent 5e9931fa03
commit 30669f8058
12 changed files with 261 additions and 26 deletions

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fdroid.fdroid.views.swap.SwapConnecting
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20sp"
android:padding="30dp"
android:textAlignment="center"
android:text="@string/swap_connecting" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progress"
tools:text="Downloading index from http://10.0.0.4:8888/fdroid/repo"
android:padding="30dp" />
</org.fdroid.fdroid.views.swap.SwapConnecting>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fdroid.fdroid.views.swap.SwapSuccessView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</org.fdroid.fdroid.views.swap.SwapSuccessView>

View File

@ -344,4 +344,5 @@
<string name="wifi_warning_public">May work</string>
<string name="wifi_warning_private">Promising</string>
<string name="wifi_warning_personal">Best bet</string>
<string name="swap_connecting">Connecting</string>
</resources>

View File

@ -16,6 +16,8 @@ import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.ProgressListener;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.localrepo.peers.Peer;
import java.lang.annotation.Retention;
@ -119,6 +121,7 @@ public class SwapManager {
public static final int STEP_JOIN_WIFI = 3;
public static final int STEP_SHOW_NFC = 4;
public static final int STEP_WIFI_QR = 5;
public static final int STEP_CONNECTING = 6;
private @SwapStep int step = STEP_INTRO;
@ -140,17 +143,48 @@ public class SwapManager {
return appsToSwap;
}
public UpdateService.UpdateReceiver connectTo(@NonNull Peer peer) {
if (peer != this.peer) {
Log.e(TAG, "Oops, got a different peer to swap with than initially planned.");
}
return UpdateService.updateRepoNow(peer.getRepoAddress(), context);
}
/**
* Ensure that we don't get put into an incorrect state, by forcing people to pass valid
* states to setStep. Ideally this would be done by requiring an enum or something to
* be passed rather than in integer, however that is harder to persist on disk than an int.
* This is the same as, e.g. {@link Context#getSystemService(String)}
*/
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR})
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR,
STEP_CONNECTING})
@Retention(RetentionPolicy.SOURCE)
public @interface SwapStep {}
// =================================================
// Have selected a specific peer to swap with
// (Rather than showing a generic QR code to scan)
// =================================================
@Nullable
private Peer peer;
public void swapWith(Peer peer) {
this.peer = peer;
}
public boolean isConnectingWithPeer() {
return peer != null;
}
@Nullable
public Peer getPeer() {
return peer;
}
// ==========================================
// Remember apps user wants to swap
// ==========================================

View File

@ -12,6 +12,11 @@ public class BluetoothPeer implements Peer {
this.device = device;
}
@Override
public String toString() {
return getName();
}
@Override
public String getName() {
return "Bluetooth: " + device.getName();
@ -24,9 +29,14 @@ public class BluetoothPeer implements Peer {
@Override
public boolean equals(Peer peer) {
return peer != null && peer instanceof BluetoothPeer && ((BluetoothPeer)peer).device.getAddress() == device.getAddress();
return peer != null && peer instanceof BluetoothPeer && ((BluetoothPeer)peer).device.getAddress().equals(device.getAddress());
}
@Override
public String getRepoAddress() {
return "bluetooth://" + device.getAddress() + "/fdroid/repo";
}
@Override
public int describeContents() {
return 0;

View File

@ -14,6 +14,11 @@ public class BonjourPeer implements Peer {
this.serviceInfo = serviceInfo;
}
@Override
public String toString() {
return getName();
}
@Override
public String getName() {
return "Bonjour: " + serviceInfo.getName();
@ -34,6 +39,10 @@ public class BonjourPeer implements Peer {
return false;
}
@Override
public String getRepoAddress() {
return serviceInfo.getURL();
}
@Override
public int describeContents() {

View File

@ -11,4 +11,5 @@ public interface Peer extends Parcelable {
boolean equals(Peer peer);
String getRepoAddress();
}

View File

@ -113,7 +113,7 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
getActivity().onJoinWifiComplete();
getActivity().showSelectApps();
return true;
}
});
@ -127,7 +127,7 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
@Override
public int getPreviousStep() {
return SwapManager.STEP_SELECT_APPS;
return SwapManager.STEP_INTRO;
}
@ColorRes

View File

@ -124,7 +124,7 @@ public class SelectAppsView extends ListView implements
@Override
public int getPreviousStep() {
return SwapManager.STEP_INTRO;
return getState().isConnectingWithPeer() ? SwapManager.STEP_JOIN_WIFI : SwapManager.STEP_INTRO;
}
@ColorRes

View File

@ -18,6 +18,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
@ -32,6 +33,8 @@ import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapManager;
import org.fdroid.fdroid.localrepo.peers.Peer;
import java.util.ArrayList;
public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView {
private static final String TAG = "StartSwapView";
@ -63,7 +66,7 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
private class PeopleNearbyAdapter extends ArrayAdapter<Peer> {
public PeopleNearbyAdapter(Context context) {
super(context, 0, new Peer[] {});
super(context, 0, new ArrayList<Peer>());
}
@Override
@ -108,6 +111,8 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
uiInitBluetooth();
uiInitWifi();
uiInitButtons();
uiUpdatePeersInfo();
}
private void uiInitButtons() {
@ -140,6 +145,14 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
peopleNearbyList.setAdapter(adapter);
uiUpdatePeersInfo();
peopleNearbyList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Peer peer = adapter.getItem(position);
onPeerSelected(peer);
}
});
getContext().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@ -175,6 +188,9 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
viewBluetoothId = (TextView)findViewById(R.id.device_id_bluetooth);
viewBluetoothId.setText(bluetooth.getName());
int textResource = getManager().isBluetoothDiscoverable() ? R.string.swap_visible_bluetooth : R.string.swap_not_visible_bluetooth;
textBluetoothVisible.setText(textResource);
Switch bluetoothSwitch = ((Switch) findViewById(R.id.switch_bluetooth));
bluetoothSwitch.setChecked(getManager().isBluetoothDiscoverable());
bluetoothSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@ -183,13 +199,13 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
if (isChecked) {
getManager().ensureBluetoothDiscoverable();
getManager().scanForPeers();
textBluetoothVisible.setText(getContext().getString(R.string.swap_visible_bluetooth));
textBluetoothVisible.setText(R.string.swap_visible_bluetooth);
uiUpdatePeersInfo();
// TODO: When they deny the request for enabling bluetooth, we need to disable this switch...
} else {
getManager().cancelScanningForPeers();
getManager().makeBluetoothNonDiscoverable();
textBluetoothVisible.setText(getContext().getString(R.string.swap_not_visible_bluetooth));
textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth);
uiUpdatePeersInfo();
}
}
@ -206,16 +222,19 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
viewWifiId = (TextView)findViewById(R.id.device_id_wifi);
viewWifiNetwork = (TextView)findViewById(R.id.wifi_network);
int textResource = getManager().isBonjourDiscoverable() ? R.string.swap_visible_wifi : R.string.swap_not_visible_wifi;
textWifiVisible.setText(textResource);
Switch wifiSwitch = (Switch)findViewById(R.id.switch_wifi);
wifiSwitch.setChecked(getManager().isBonjourDiscoverable());
wifiSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
textWifiVisible.setText(getContext().getString(R.string.swap_visible_wifi));
textWifiVisible.setText(R.string.swap_visible_wifi);
uiUpdatePeersInfo();
} else {
textWifiVisible.setText(getContext().getString(R.string.swap_not_visible_wifi));
textWifiVisible.setText(R.string.swap_not_visible_wifi);
uiUpdatePeersInfo();
}
}
@ -239,6 +258,10 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
}
}
private void onPeerSelected(Peer peer) {
getActivity().swapWith(peer);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;

View File

@ -0,0 +1,108 @@
package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.view.MenuItemCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.ProgressListener;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.localrepo.SwapManager;
import org.fdroid.fdroid.localrepo.peers.Peer;
public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity.InnerView {
private final static String TAG = "SwapConnecting";
public SwapConnecting(Context context) {
super(context);
}
public SwapConnecting(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwapConnecting(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwapConnecting(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity)getContext();
}
private SwapManager getManager() {
return getActivity().getState();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
Peer peer = getManager().getPeer();
if (peer == null) {
Log.e(TAG, "Cannot find the peer to connect to.");
// TODO: Don't go to the selected apps, rather show a Toast message and then
// go to the intro screen.
getActivity().showSelectApps();
return;
}
String heading = getContext().getString(R.string.status_connecting_to_repo, getActivity().getState().getPeer().getName());
((TextView) findViewById(R.id.heading)).setText(heading);
UpdateService.UpdateReceiver receiver = getManager().connectTo(peer);
receiver.hideDialog();
receiver.setListener(new ProgressListener() {
@Override
public void onProgress(Event event) {
((TextView) findViewById(R.id.progress)).setText(event.data.getString(UpdateService.EXTRA_ADDRESS));
}
});
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return true;
}
@Override
public int getStep() {
return SwapManager.STEP_CONNECTING;
}
@Override
public int getPreviousStep() {
return SwapManager.STEP_SELECT_APPS;
}
@ColorRes
public int getToolbarColour() {
return getResources().getColor(R.color.swap_blue);
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_connecting);
}
}

View File

@ -32,6 +32,7 @@ import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapManager;
import org.fdroid.fdroid.localrepo.peers.Peer;
import java.util.Arrays;
import java.util.HashSet;
@ -191,8 +192,8 @@ public class SwapWorkflowActivity extends AppCompatActivity {
if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) {
updateSwappableAppsTask = new PrepareFullSwapRepo(state.getAppsToSwap());
updateSwappableAppsTask.execute();
} else {
showJoinWifi();
} else if (!attemptToShowNfc()) {
showWifiQr();
}
}
@ -208,25 +209,30 @@ public class SwapWorkflowActivity extends AppCompatActivity {
/**
* Once the UpdateAsyncTask has finished preparing our repository index, we can
* show the next screen to the user.
* show the next screen to the user. This will be one of two things:
* * If we directly selected a peer to swap with initially, we will skip straight to getting
* the list of apps from that device.
* * Alternatively, if we didn't have a person to connect to, and instead clicked "Scan QR Code",
* then we want to show a QR code or NFC dialog.
*/
private void onLocalRepoPrepared() {
updateSwappableAppsTask = null;
hasPreparedLocalRepo = true;
showJoinWifi();
if (state.isConnectingWithPeer()) {
startSwappingWithPeer();
} else if (!attemptToShowNfc()) {
showWifiQr();
};
}
private void startSwappingWithPeer() {
inflateInnerView(R.layout.swap_connecting);
}
private void showJoinWifi() {
inflateInnerView(R.layout.swap_join_wifi);
}
public void onJoinWifiComplete() {
ensureLocalRepoRunning();
if (!attemptToShowNfc()) {
showWifiQr();
}
}
public void showWifiQr() {
inflateInnerView(R.layout.swap_wifi_qr);
}
@ -247,15 +253,16 @@ public class SwapWorkflowActivity extends AppCompatActivity {
return false;
}
private void ensureLocalRepoRunning() {
getState().enableSwapping();
}
public void stopSwapping() {
getState().disableSwapping();
finish();
}
public void swapWith(Peer peer) {
state.swapWith(peer);
showSelectApps();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);