From 38059ec324fbc03a2c841a4f266c02a331ed1a7d Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sat, 23 May 2015 13:17:33 +1000 Subject: [PATCH] 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. --- .../fdroid/fdroid/localrepo/SwapState.java | 73 +++++++++++++++++++ .../views/swap/SwapWorkflowActivity.java | 49 ++++++++++--- .../fdroid/views/swap/views/JoinWifiView.java | 6 ++ .../fdroid/views/swap/views/NfcView.java | 6 ++ .../views/swap/views/SelectAppsView.java | 6 ++ .../views/swap/views/StartSwapView.java | 8 +- .../fdroid/views/swap/views/WifiQrView.java | 6 ++ 7 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 F-Droid/src/org/fdroid/fdroid/localrepo/SwapState.java diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapState.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapState.java new file mode 100644 index 000000000..1783eb000 --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapState.java @@ -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 {} +} diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java index f8fc37ace..72e8e4b37 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -28,6 +28,7 @@ import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.localrepo.LocalRepoManager; +import org.fdroid.fdroid.localrepo.SwapState; import java.util.Set; import java.util.Timer; @@ -37,18 +38,20 @@ public class SwapWorkflowActivity extends FragmentActivity { private ViewGroup container; - private enum State { - INTRO, SELECT_APPS, JOIN_WIFI - } - public interface InnerView { /** @return True if the menu should be shown. */ 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 State currentState = State.INTRO; + private SwapState state; private InnerView currentView; private boolean hasPreparedLocalRepo = false; private UpdateAsyncTask updateSwappableAppsTask = null; @@ -57,8 +60,10 @@ public class SwapWorkflowActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + state = SwapState.load(this); setContentView(R.layout.swap_activity); container = (ViewGroup) findViewById(R.id.fragment_container); + showRelevantView(); } @Override @@ -72,12 +77,37 @@ public class SwapWorkflowActivity extends FragmentActivity { @Override protected void onResume() { super.onResume(); - showView(); + showRelevantView(); } - private void showView() { - if (currentState == State.INTRO) { - showIntro(); + private void showRelevantView() { + 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(); + 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(); View view = ((LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false); currentView = (InnerView)view; + state.setStep(currentView.getStep()); container.addView(view); supportInvalidateOptionsMenu(); } diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/JoinWifiView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/JoinWifiView.java index 653db430b..e77d0b9a6 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/JoinWifiView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/JoinWifiView.java @@ -22,6 +22,7 @@ import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.localrepo.SwapState; import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; @@ -117,4 +118,9 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity }); return true; } + + @Override + public int getStep() { + return SwapState.STEP_JOIN_WIFI; + } } diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java index 63ce23c61..b3a566203 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java @@ -15,6 +15,7 @@ import android.widget.RelativeLayout; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.localrepo.SwapState; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView { @@ -67,4 +68,9 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne }); return true; } + + @Override + public int getStep() { + return SwapState.STEP_SHOW_NFC; + } } diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/SelectAppsView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/SelectAppsView.java index 7a17788da..2917e8c02 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/SelectAppsView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/SelectAppsView.java @@ -36,6 +36,7 @@ import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.InstalledAppProvider; import org.fdroid.fdroid.localrepo.LocalRepoManager; +import org.fdroid.fdroid.localrepo.SwapState; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; import java.util.HashSet; @@ -142,6 +143,11 @@ public class SelectAppsView extends ListView implements return true; } + @Override + public int getStep() { + return SwapState.STEP_SELECT_APPS; + } + private void toggleAppSelected(int position) { Cursor c = (Cursor) adapter.getItem(position - 1); String packageName = c.getString(c.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)); diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/StartSwapView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/StartSwapView.java index 72560f92d..a681f3de7 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/StartSwapView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/StartSwapView.java @@ -12,6 +12,7 @@ import android.view.View; import android.widget.LinearLayout; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.localrepo.SwapState; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView { @@ -34,8 +35,6 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity. super(context, attrs, defStyleAttr, defStyleRes); } - - private SwapWorkflowActivity getActivity() { // TODO: Try and find a better way to get to the SwapActivity, which makes less asumptions. return (SwapWorkflowActivity)getContext(); @@ -58,4 +57,9 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity. public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { return false; } + + @Override + public int getStep() { + return SwapState.STEP_INTRO; + } } diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java index 09b5d66c6..47120a492 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java @@ -30,6 +30,7 @@ import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.QrGenAsyncTask; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.localrepo.SwapState; import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; @@ -106,6 +107,11 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner return false; } + @Override + public int getStep() { + return SwapState.STEP_WIFI_QR; + } + private void setUIFromWifi() { if (TextUtils.isEmpty(FDroidApp.repo.address))