WIP: Initial state handling for swap process.

The state is saved to a preference file, but that is abstracted from
the SwapWorkflowActivity. It interacts with a SwapState object, which
is relatively safe in that you should not be able to save it into an
invalid state.

Note: At this point it is not tied to any service. I'm not sure it will
ever have to be either, as the service needs to persist state somewhere
anyway, so that will probably also end up saving to a preferences file
too.
This commit is contained in:
Peter Serwylo 2015-05-23 13:17:33 +10:00
parent 1b2678d6ed
commit 38059ec324
7 changed files with 143 additions and 11 deletions

View File

@ -0,0 +1,73 @@
package org.fdroid.fdroid.localrepo;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class SwapState {
private static final String SHARED_PREFERENCES = "swap-state";
public static final int STEP_INTRO = 1;
public static final int STEP_SELECT_APPS = 2;
public static final int STEP_JOIN_WIFI = 3;
public static final int STEP_SHOW_NFC = 4;
public static final int STEP_WIFI_QR = 5;
private int step;
@NonNull
private final Context context;
private SwapState(@NonNull Context context) {
this.context = context;
}
/**
* Current screen that the swap process is up to.
* Will be one of the SwapState.STEP_* values.
*/
@SwapStep
public int getStep() {
return step;
}
public SwapState setStep(@SwapStep int step) {
this.step = step;
persist();
return this;
}
private static final String KEY_STEP = "step";
@NonNull
public static SwapState load(@NonNull Context context) {
SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
@SwapStep int step = preferences.getInt(KEY_STEP, STEP_INTRO);
return new SwapState(context)
.setStep(step);
}
private void persist() {
SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_APPEND);
preferences.edit()
.putInt(KEY_STEP, step)
.commit();
}
/**
* 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})
@Retention(RetentionPolicy.SOURCE)
public @interface SwapStep {}
}

View File

@ -28,6 +28,7 @@ import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.localrepo.LocalRepoManager; import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapState;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.Timer;
@ -37,18 +38,20 @@ public class SwapWorkflowActivity extends FragmentActivity {
private ViewGroup container; private ViewGroup container;
private enum State {
INTRO, SELECT_APPS, JOIN_WIFI
}
public interface InnerView { public interface InnerView {
/** @return True if the menu should be shown. */ /** @return True if the menu should be shown. */
boolean buildMenu(Menu menu, @NonNull MenuInflater inflater); boolean buildMenu(Menu menu, @NonNull MenuInflater inflater);
/** @return The step that this view represents. */
@SwapState.SwapStep int getStep();
// TODO: Handle back presses with a method like this:
// @SwapState.SwapStep int getPreviousStep();
} }
private static final int CONNECT_TO_SWAP = 1; private static final int CONNECT_TO_SWAP = 1;
private State currentState = State.INTRO; private SwapState state;
private InnerView currentView; private InnerView currentView;
private boolean hasPreparedLocalRepo = false; private boolean hasPreparedLocalRepo = false;
private UpdateAsyncTask updateSwappableAppsTask = null; private UpdateAsyncTask updateSwappableAppsTask = null;
@ -57,8 +60,10 @@ public class SwapWorkflowActivity extends FragmentActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
state = SwapState.load(this);
setContentView(R.layout.swap_activity); setContentView(R.layout.swap_activity);
container = (ViewGroup) findViewById(R.id.fragment_container); container = (ViewGroup) findViewById(R.id.fragment_container);
showRelevantView();
} }
@Override @Override
@ -72,12 +77,37 @@ public class SwapWorkflowActivity extends FragmentActivity {
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
showView(); showRelevantView();
} }
private void showView() { private void showRelevantView() {
if (currentState == State.INTRO) { if (currentView != null && currentView.getStep() == state.getStep()) {
// Already showing the currect step, so don't bother changing anything.
return;
}
switch(state.getStep()) {
case SwapState.STEP_INTRO:
showIntro(); showIntro();
break;
case SwapState.STEP_SELECT_APPS:
showSelectApps();
break;
case SwapState.STEP_SHOW_NFC:
showNfc();
break;
case SwapState.STEP_JOIN_WIFI:
showJoinWifi();
break;
case SwapState.STEP_WIFI_QR:
showWifiQr();
break;
}
}
private void showNfc() {
if (!attemptToShowNfc()) {
showWifiQr();
} }
} }
@ -85,6 +115,7 @@ public class SwapWorkflowActivity extends FragmentActivity {
container.removeAllViews(); container.removeAllViews();
View view = ((LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false); View view = ((LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false);
currentView = (InnerView)view; currentView = (InnerView)view;
state.setStep(currentView.getStep());
container.addView(view); container.addView(view);
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
} }

View File

@ -22,6 +22,7 @@ import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapState;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
@ -117,4 +118,9 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
}); });
return true; return true;
} }
@Override
public int getStep() {
return SwapState.STEP_JOIN_WIFI;
}
} }

View File

@ -15,6 +15,7 @@ import android.widget.RelativeLayout;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapState;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView { public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
@ -67,4 +68,9 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
}); });
return true; return true;
} }
@Override
public int getStep() {
return SwapState.STEP_SHOW_NFC;
}
} }

View File

@ -36,6 +36,7 @@ import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider; import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.localrepo.LocalRepoManager; import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapState;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
import java.util.HashSet; import java.util.HashSet;
@ -142,6 +143,11 @@ public class SelectAppsView extends ListView implements
return true; return true;
} }
@Override
public int getStep() {
return SwapState.STEP_SELECT_APPS;
}
private void toggleAppSelected(int position) { private void toggleAppSelected(int position) {
Cursor c = (Cursor) adapter.getItem(position - 1); Cursor c = (Cursor) adapter.getItem(position - 1);
String packageName = c.getString(c.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)); String packageName = c.getString(c.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID));

View File

@ -12,6 +12,7 @@ import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapState;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView { public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView {
@ -34,8 +35,6 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
super(context, attrs, defStyleAttr, defStyleRes); super(context, attrs, defStyleAttr, defStyleRes);
} }
private SwapWorkflowActivity getActivity() { private SwapWorkflowActivity getActivity() {
// TODO: Try and find a better way to get to the SwapActivity, which makes less asumptions. // TODO: Try and find a better way to get to the SwapActivity, which makes less asumptions.
return (SwapWorkflowActivity)getContext(); return (SwapWorkflowActivity)getContext();
@ -58,4 +57,9 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false; return false;
} }
@Override
public int getStep() {
return SwapState.STEP_INTRO;
}
} }

View File

@ -30,6 +30,7 @@ import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.QrGenAsyncTask; import org.fdroid.fdroid.QrGenAsyncTask;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapState;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
@ -106,6 +107,11 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner
return false; return false;
} }
@Override
public int getStep() {
return SwapState.STEP_WIFI_QR;
}
private void setUIFromWifi() { private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address)) if (TextUtils.isEmpty(FDroidApp.repo.address))