diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a8cdb0c5e..c7b81c15b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,7 +79,8 @@ errorprone: unzip -qq -d $ANDROID_HOME emulator-linux-5264690.zip; set +x; fi - - grep Revision $ANDROID_HOME/emulator/source.properties + - grep -v '^License' $ANDROID_HOME/tools/source.properties + $ANDROID_HOME/emulator/source.properties - alias sdkmanager - echo y | sdkmanager "platforms;android-$AVD_SDK" > /dev/null diff --git a/app/src/full/java/org/fdroid/fdroid/localrepo/SwapService.java b/app/src/full/java/org/fdroid/fdroid/localrepo/SwapService.java index a205ab066..332cea135 100644 --- a/app/src/full/java/org/fdroid/fdroid/localrepo/SwapService.java +++ b/app/src/full/java/org/fdroid/fdroid/localrepo/SwapService.java @@ -15,7 +15,7 @@ import android.net.Uri; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.IBinder; -import android.support.annotation.IntDef; +import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; @@ -46,8 +46,6 @@ import rx.schedulers.Schedulers; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; @@ -129,43 +127,21 @@ public class SwapService extends Service { return peerFinder; } - // ========================================================== - // Manage the current step - // ("Step" refers to the current view being shown in the UI) - // ========================================================== - 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; - public static final int STEP_CONNECTING = 6; - public static final int STEP_SUCCESS = 7; - public static final int STEP_CONFIRM_SWAP = 8; - /** - * Special view, that we don't really want to actually store against the - * {@link SwapService#step}. Rather, we use it for the purpose of specifying - * we are in the state waiting for the {@link SwapService} to get started and - * bound to the {@link SwapWorkflowActivity}. - */ - public static final int STEP_INITIAL_LOADING = 9; - - @SwapStep - private int step = STEP_INTRO; + @LayoutRes + private int currentView = STEP_INTRO; /** * Current screen that the swap process is up to. - * Will be one of the SwapState.STEP_* values. */ - @SwapStep - public int getStep() { - return step; + @LayoutRes + public int getCurrentView() { + return currentView; } - public SwapService setStep(@SwapStep int step) { - this.step = step; - return this; + public void setCurrentView(@LayoutRes int currentView) { + this.currentView = currentView; } @NonNull @@ -269,18 +245,6 @@ public class SwapService extends Service { return peerRepo; } - /** - * 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, - STEP_CONNECTING, STEP_SUCCESS, STEP_CONFIRM_SWAP, STEP_INITIAL_LOADING}) - @Retention(RetentionPolicy.SOURCE) - public @interface SwapStep { - } - // ================================================= // Have selected a specific peer to swap with // (Rather than showing a generic QR code to scan) diff --git a/app/src/full/java/org/fdroid/fdroid/localrepo/SwapView.java b/app/src/full/java/org/fdroid/fdroid/localrepo/SwapView.java new file mode 100644 index 000000000..9404ad14f --- /dev/null +++ b/app/src/full/java/org/fdroid/fdroid/localrepo/SwapView.java @@ -0,0 +1,80 @@ +package org.fdroid.fdroid.localrepo; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.support.annotation.ColorInt; +import android.support.annotation.LayoutRes; +import android.util.AttributeSet; +import android.widget.RelativeLayout; +import org.fdroid.fdroid.R; +import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; + +/** + * A {@link android.view.View} that registers to handle the swap events from + * {@link SwapService}. + */ +public class SwapView extends RelativeLayout { + public static final String TAG = "SwapView"; + + @ColorInt + public final int toolbarColor; + public final String toolbarTitle; + + private int layoutResId; + + protected String currentFilterString; + + public SwapView(Context context) { + this(context, null); + } + + public SwapView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SwapView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + @TargetApi(21) + public SwapView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.SwapView, 0, 0); + toolbarColor = a.getColor(R.styleable.SwapView_toolbarColor, + getResources().getColor(R.color.swap_blue)); + toolbarTitle = a.getString(R.styleable.SwapView_toolbarTitle); + a.recycle(); + } + + @LayoutRes + public int getLayoutResId() { + return layoutResId; + } + + public void setLayoutResId(@LayoutRes int layoutResId) { + this.layoutResId = layoutResId; + } + + public String getCurrentFilterString() { + return this.currentFilterString; + } + + public void setCurrentFilterString(String currentFilterString) { + this.currentFilterString = currentFilterString; + } + + public SwapWorkflowActivity getActivity() { + return (SwapWorkflowActivity) getContext(); + } + + @ColorInt + public int getToolbarColour() { + return toolbarColor; + } + + public String getToolbarTitle() { + return toolbarTitle; + } +} diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceive.java b/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceive.java deleted file mode 100644 index 2e23d4a05..000000000 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceive.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.fdroid.fdroid.views.swap; - -import android.annotation.TargetApi; -import android.content.Context; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import org.fdroid.fdroid.R; -import org.fdroid.fdroid.data.NewRepoConfig; -import org.fdroid.fdroid.localrepo.SwapService; - -public class ConfirmReceive extends RelativeLayout implements SwapWorkflowActivity.InnerView { - - private NewRepoConfig config; - - public ConfirmReceive(Context context) { - super(context); - } - - public ConfirmReceive(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ConfirmReceive(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @TargetApi(21) - public ConfirmReceive(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - findViewById(R.id.no_button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().denySwap(); - } - }); - - findViewById(R.id.yes_button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().swapWith(config); - } - }); - } - - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_CONFIRM_SWAP; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_INTRO; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_confirm); - } - - public void setup(NewRepoConfig config) { - this.config = config; - TextView descriptionTextView = (TextView) findViewById(R.id.text_description); - descriptionTextView.setText(getResources().getString(R.string.swap_confirm_connect, config.getHost())); - } -} diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceiveView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceiveView.java new file mode 100644 index 000000000..7cce11196 --- /dev/null +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/ConfirmReceiveView.java @@ -0,0 +1,54 @@ +package org.fdroid.fdroid.views.swap; + +import android.annotation.TargetApi; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import org.fdroid.fdroid.R; +import org.fdroid.fdroid.data.NewRepoConfig; +import org.fdroid.fdroid.localrepo.SwapView; + +public class ConfirmReceiveView extends SwapView { + + private NewRepoConfig config; + + public ConfirmReceiveView(Context context) { + super(context); + } + + public ConfirmReceiveView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ConfirmReceiveView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(21) + public ConfirmReceiveView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + findViewById(R.id.no_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().denySwap(); + } + }); + + findViewById(R.id.yes_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().swapWith(config); + } + }); + } + + public void setup(NewRepoConfig config) { + this.config = config; + } +} diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapConnecting.java b/app/src/full/java/org/fdroid/fdroid/views/swap/ConnectingView.java similarity index 74% rename from app/src/full/java/org/fdroid/fdroid/views/swap/SwapConnecting.java rename to app/src/full/java/org/fdroid/fdroid/views/swap/ConnectingView.java index d35ea3492..9a1208bff 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapConnecting.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/ConnectingView.java @@ -5,49 +5,39 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; import android.support.v4.content.LocalBroadcastManager; import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; import android.view.View; import android.widget.Button; -import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.TextView; - import org.fdroid.fdroid.R; import org.fdroid.fdroid.UpdateService; -import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; -// TODO: Use this for the "Preparing local repo" dialog also. -public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity.InnerView { +public class ConnectingView extends SwapView { @SuppressWarnings("unused") - private static final String TAG = "SwapConnecting"; + private static final String TAG = "ConnectingView"; - public SwapConnecting(Context context) { + public ConnectingView(Context context) { super(context); } - public SwapConnecting(Context context, AttributeSet attrs) { + public ConnectingView(Context context, AttributeSet attrs) { super(context, attrs); } @TargetApi(11) - public SwapConnecting(Context context, AttributeSet attrs, int defStyleAttr) { + public ConnectingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(21) - public SwapConnecting(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public ConnectingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -83,9 +73,9 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity /** * Listens for feedback about a local repository being prepared: - * * Apk files copied to the LocalHTTPD webroot - * * index.html file prepared - * * Icons will be copied to the webroot in the background and so are not part of this process. + * * Apk files copied to the LocalHTTPD webroot + * * index.html file prepared + * * Icons will be copied to the webroot in the background and so are not part of this process. */ class PrepareSwapReceiver extends Receiver { @@ -116,7 +106,7 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity /** * Listens for feedback about a repo update process taking place. - * * Tracks an index.jar download and show the progress messages + * Tracks an index.jar download and show the progress messages */ class ConnectSwapReceiver extends Receiver { @@ -146,7 +136,7 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity @Override protected void onComplete() { - getActivity().showSwapConnected(); + getActivity().inflateSwapView(R.layout.swap_success); } } @@ -165,8 +155,9 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity public void onReceive(Context context, Intent intent) { TextView progressText = (TextView) findViewById(R.id.heading); - TextView errorText = (TextView) findViewById(R.id.error); - Button backButton = (Button) findViewById(R.id.back); + ProgressBar progressBar = findViewById(R.id.progress_bar); + TextView errorText = (TextView) findViewById(R.id.error); + Button backButton = (Button) findViewById(R.id.back); String message; if (intent.hasExtra(getMessageExtra())) { @@ -177,11 +168,13 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity } progressText.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.VISIBLE); errorText.setVisibility(View.GONE); backButton.setVisibility(View.GONE); if (isError(intent)) { progressText.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); errorText.setVisibility(View.VISIBLE); backButton.setVisibility(View.VISIBLE); return; @@ -192,29 +185,4 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity } } } - - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_CONNECTING; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_SELECT_APPS; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_bright_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_connecting); - } } diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/InitialLoadingView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/InitialLoadingView.java deleted file mode 100644 index 56d2fba05..000000000 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/InitialLoadingView.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.fdroid.fdroid.views.swap; - -import android.annotation.TargetApi; -import android.content.Context; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; -import android.widget.RelativeLayout; - -import org.fdroid.fdroid.R; -import org.fdroid.fdroid.localrepo.SwapService; - -public class InitialLoadingView extends RelativeLayout implements SwapWorkflowActivity.InnerView { - - public InitialLoadingView(Context context) { - super(context); - } - - public InitialLoadingView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @TargetApi(21) - public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_INITIAL_LOADING; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_JOIN_WIFI; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap); - } -} diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/JoinWifiView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/JoinWifiView.java index ef59e8823..ac8454e47 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/JoinWifiView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/JoinWifiView.java @@ -6,25 +6,18 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.WifiManager; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; import android.support.v4.content.LocalBroadcastManager; -import android.support.v4.view.MenuItemCompat; import android.text.TextUtils; import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.widget.ImageView; -import android.widget.RelativeLayout; import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; -import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.net.WifiStateChangeService; -public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity.InnerView { +public class JoinWifiView extends SwapView { public JoinWifiView(Context context) { super(context); @@ -43,10 +36,6 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -106,42 +95,6 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity getActivity().startActivity(new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)); } - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.swap_next, menu); - MenuItem next = menu.findItem(R.id.action_next); - MenuItemCompat.setShowAsAction(next, - MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT); - next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - getActivity().showSelectApps(); - return true; - } - }); - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_JOIN_WIFI; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_INTRO; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_join_same_wifi); - } - private final BroadcastReceiver onWifiStateChange = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/NfcView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/NfcView.java index 5d2ef5760..43c8989a0 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/NfcView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/NfcView.java @@ -2,21 +2,14 @@ package org.fdroid.fdroid.views.swap; import android.annotation.TargetApi; import android.content.Context; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; -import android.support.v4.view.MenuItemCompat; import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.RelativeLayout; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; -import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; -public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView { +public class NfcView extends SwapView { public NfcView(Context context) { super(context); @@ -35,10 +28,6 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -50,40 +39,4 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne } }); } - - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.swap_skip, menu); - MenuItem next = menu.findItem(R.id.action_next); - MenuItemCompat.setShowAsAction(next, - MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT); - next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - getActivity().showWifiQr(); - return true; - } - }); - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_SHOW_NFC; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_JOIN_WIFI; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_nfc_title); - } } diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SelectAppsView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SelectAppsView.java index 5f0d7a496..9068be658 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SelectAppsView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SelectAppsView.java @@ -8,22 +8,16 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.ColorRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.CursorAdapter; -import android.support.v7.widget.SearchView; import android.text.TextUtils; import android.util.AttributeSet; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; @@ -32,16 +26,13 @@ import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; - import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.InstalledAppProvider; import org.fdroid.fdroid.data.Schema.InstalledAppTable; import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; -public class SelectAppsView extends ListView implements - SwapWorkflowActivity.InnerView, - LoaderManager.LoaderCallbacks, - SearchView.OnQueryTextListener { +public class SelectAppsView extends SwapView implements LoaderManager.LoaderCallbacks { public SelectAppsView(Context context) { super(context); @@ -60,86 +51,34 @@ public class SelectAppsView extends ListView implements super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - private SwapService getState() { return getActivity().getState(); } - private static final int LOADER_INSTALLED_APPS = 253341534; - + private ListView listView; private AppListAdapter adapter; - private String currentFilterString; @Override protected void onFinishInflate() { super.onFinishInflate(); - adapter = new AppListAdapter(this, getContext(), + listView = findViewById(R.id.list); + adapter = new AppListAdapter(listView, getContext(), getContext().getContentResolver().query(InstalledAppProvider.getContentUri(), InstalledAppTable.Cols.ALL, null, null, null)); - setAdapter(adapter); - setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + listView.setAdapter(adapter); + listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); // either reconnect with an existing loader or start a new one - getActivity().getSupportLoaderManager().initLoader(LOADER_INSTALLED_APPS, null, this); + getActivity().getSupportLoaderManager().initLoader(R.layout.swap_select_apps, null, this); - setOnItemClickListener(new AdapterView.OnItemClickListener() { + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { toggleAppSelected(position); } }); } - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - - inflater.inflate(R.menu.swap_next_search, menu); - MenuItem nextMenuItem = menu.findItem(R.id.action_next); - int flags = MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT; - MenuItemCompat.setShowAsAction(nextMenuItem, flags); - nextMenuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - getActivity().onAppsSelected(); - return true; - } - }); - - SearchView searchView = new SearchView(getActivity()); - - MenuItem searchMenuItem = menu.findItem(R.id.action_search); - MenuItemCompat.setActionView(searchMenuItem, searchView); - MenuItemCompat.setShowAsAction(searchMenuItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); - - searchView.setOnQueryTextListener(this); - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_SELECT_APPS; - } - - @Override - public int getPreviousStep() { - // TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it - // so that it is, or so that this doesn't go back there. - return getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : SwapService.STEP_JOIN_WIFI; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_bright_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_choose_apps); - } - private void toggleAppSelected(int position) { Cursor c = (Cursor) adapter.getItem(position); String packageName = c.getString(c.getColumnIndex(InstalledAppTable.Cols.Package.NAME)); @@ -174,13 +113,13 @@ public class SelectAppsView extends ListView implements public void onLoadFinished(Loader loader, Cursor cursor) { adapter.swapCursor(cursor); - for (int i = 0; i < getCount(); i++) { - Cursor c = (Cursor) getItemAtPosition(i); + for (int i = 0; i < listView.getCount(); i++) { + Cursor c = (Cursor) listView.getItemAtPosition(i); String packageName = c.getString(c.getColumnIndex(InstalledAppTable.Cols.Package.NAME)); getState().ensureFDroidSelected(); for (String selected : getState().getAppsToSwap()) { if (TextUtils.equals(packageName, selected)) { - setItemChecked(i, true); + listView.setItemChecked(i, true); } } } @@ -191,26 +130,6 @@ public class SelectAppsView extends ListView implements adapter.swapCursor(null); } - @Override - public boolean onQueryTextChange(String newText) { - String newFilter = !TextUtils.isEmpty(newText) ? newText : null; - if (currentFilterString == null && newFilter == null) { - return true; - } - if (currentFilterString != null && currentFilterString.equals(newFilter)) { - return true; - } - currentFilterString = newFilter; - getActivity().getSupportLoaderManager().restartLoader(LOADER_INSTALLED_APPS, null, this); - return true; - } - - @Override - public boolean onQueryTextSubmit(String query) { - // this is not needed since we respond to every change in text - return true; - } - private class AppListAdapter extends CursorAdapter { @Nullable diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SendFDroidView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SendFDroidView.java index 60bf9fc02..30ba74da7 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SendFDroidView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SendFDroidView.java @@ -7,28 +7,23 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.LightingColorFilter; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; -import android.widget.ScrollView; import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; 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.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker; -public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.InnerView { +public class SendFDroidView extends SwapView { private static final String TAG = "SendFDroidView"; @@ -49,10 +44,6 @@ public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.I super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -96,31 +87,6 @@ public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.I LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onWifiStateChanged); } - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return false; - } - - @Override - public int getStep() { - return SwapService.STEP_INTRO; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_INTRO; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_send_fdroid); - } - @SuppressLint("HardwareIds") private void setUIFromWifi() { if (TextUtils.isEmpty(FDroidApp.repo.address)) { diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/StartSwapView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/StartSwapView.java index 03aeeb2ac..09c1558d4 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/StartSwapView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/StartSwapView.java @@ -7,16 +7,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.WifiConfiguration; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.SwitchCompat; import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; @@ -25,13 +21,13 @@ import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; -import android.widget.RelativeLayout; import android.widget.TextView; import cc.mvdan.accesspoint.WifiApControl; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.localrepo.peers.Peer; import org.fdroid.fdroid.net.WifiStateChangeService; import rx.Subscriber; @@ -40,7 +36,7 @@ import rx.Subscription; import java.util.ArrayList; @SuppressWarnings("LineLength") -public class StartSwapView extends RelativeLayout implements SwapWorkflowActivity.InnerView { +public class StartSwapView extends SwapView { private static final String TAG = "StartSwapView"; @@ -58,7 +54,6 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit super(context, attrs); } - @TargetApi(11) public StartSwapView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @@ -91,10 +86,6 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - private SwapService getManager() { return getActivity().getState(); } @@ -456,35 +447,4 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit private void onPeerSelected(Peer peer) { getActivity().swapWith(peer); } - - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return false; - } - - @Override - public int getStep() { - return SwapService.STEP_INTRO; - } - - @Override - public int getPreviousStep() { - // TODO: Currently this is handleed by the SwapWorkflowActivity as a special case, where - // if getStep is STEP_INTRO, don't even bother asking for getPreviousStep. But that is a - // bit messy. It would be nicer if this was handled using the same mechanism as everything - // else. - return SwapService.STEP_INTRO; - } - - @Override - @ColorRes - public int getToolbarColour() { - return R.color.swap_bright_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_nearby); - } - } diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapSuccessView.java similarity index 85% rename from app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java rename to app/src/full/java/org/fdroid/fdroid/views/swap/SwapSuccessView.java index 88ad58021..5fd5ac97d 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapSuccessView.java @@ -12,22 +12,16 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.support.annotation.ColorRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.content.LocalBroadcastManager; -import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.CursorAdapter; -import android.support.v7.widget.SearchView; import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -47,7 +41,7 @@ import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.Schema.AppMetadataTable; -import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.net.Downloader; import org.fdroid.fdroid.net.DownloaderService; @@ -55,35 +49,26 @@ import java.util.List; import java.util.Timer; import java.util.TimerTask; -public class SwapAppsView extends ListView implements - SwapWorkflowActivity.InnerView, - LoaderManager.LoaderCallbacks, - SearchView.OnQueryTextListener { +public class SwapSuccessView extends SwapView implements LoaderManager.LoaderCallbacks { + private static final String TAG = "SwapAppsView"; - public SwapAppsView(Context context) { + public SwapSuccessView(Context context) { super(context); } - public SwapAppsView(Context context, AttributeSet attrs) { + public SwapSuccessView(Context context, AttributeSet attrs) { super(context, attrs); } - public SwapAppsView(Context context, AttributeSet attrs, int defStyleAttr) { + public SwapSuccessView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(21) - public SwapAppsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public SwapSuccessView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - - private static final int LOADER_SWAPABLE_APPS = 759283741; - private static final String TAG = "SwapAppsView"; - private Repo repo; private AppListAdapter adapter; private String currentFilterString; @@ -102,11 +87,11 @@ public class SwapAppsView extends ListView implements adapter = new AppListAdapter(getContext(), getContext().getContentResolver().query( AppProvider.getRepoUri(repo), AppMetadataTable.Cols.ALL, null, null, null)); - - setAdapter(adapter); + ListView listView = findViewById(R.id.list); + listView.setAdapter(adapter); // either reconnect with an existing loader or start a new one - getActivity().getSupportLoaderManager().initLoader(LOADER_SWAPABLE_APPS, null, this); + getActivity().getSupportLoaderManager().initLoader(R.layout.swap_success, null, this); LocalBroadcastManager.getInstance(getActivity()).registerReceiver( pollForUpdatesReceiver, new IntentFilter(UpdateService.LOCAL_ACTION_STATUS)); @@ -148,41 +133,6 @@ public class SwapAppsView extends ListView implements }, 5000); } - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - - inflater.inflate(R.menu.swap_search, menu); - - SearchView searchView = new SearchView(getActivity()); - - MenuItem searchMenuItem = menu.findItem(R.id.action_search); - MenuItemCompat.setActionView(searchMenuItem, searchView); - MenuItemCompat.setShowAsAction(searchMenuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); - - searchView.setOnQueryTextListener(this); - return true; - } - - @Override - public int getStep() { - return SwapService.STEP_SUCCESS; - } - - @Override - public int getPreviousStep() { - return SwapService.STEP_INTRO; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_bright_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_success); - } - @Override public CursorLoader onCreateLoader(int id, Bundle args) { Uri uri = TextUtils.isEmpty(currentFilterString) @@ -203,26 +153,6 @@ public class SwapAppsView extends ListView implements adapter.swapCursor(null); } - @Override - public boolean onQueryTextChange(String newText) { - String newFilter = !TextUtils.isEmpty(newText) ? newText : null; - if (currentFilterString == null && newFilter == null) { - return true; - } - if (currentFilterString != null && currentFilterString.equals(newFilter)) { - return true; - } - currentFilterString = newFilter; - getActivity().getSupportLoaderManager().restartLoader(LOADER_SWAPABLE_APPS, null, this); - return true; - } - - @Override - public boolean onQueryTextSubmit(String query) { - // this is not needed since we respond to every change in text - return true; - } - private class AppListAdapter extends CursorAdapter { private class ViewHolder { diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java index c55d773b6..ee92c4dca 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -17,20 +17,25 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.provider.Settings; -import android.support.annotation.ColorRes; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.StringRes; import android.support.v4.content.LocalBroadcastManager; +import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.SearchView; import android.support.v7.widget.Toolbar; +import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import android.widget.Toast; import cc.mvdan.accesspoint.WifiApControl; import com.google.zxing.integration.android.IntentIntegrator; @@ -48,6 +53,7 @@ import org.fdroid.fdroid.installer.InstallManagerService; import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.localrepo.LocalRepoManager; import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.localrepo.peers.Peer; import org.fdroid.fdroid.net.BluetoothDownloader; import org.fdroid.fdroid.net.HttpDownloader; @@ -68,6 +74,7 @@ import java.util.TimerTask; */ @SuppressWarnings("LineLength") public class SwapWorkflowActivity extends AppCompatActivity { + private static final String TAG = "SwapWorkflowActivity"; /** * When connecting to a swap, we then go and initiate a connection with that @@ -87,28 +94,6 @@ public class SwapWorkflowActivity extends AppCompatActivity { private ViewGroup container; - /** - * A UI component (subclass of {@link View}) which forms part of the swap workflow. - * There is a one to one mapping between an {@link org.fdroid.fdroid.views.swap.SwapWorkflowActivity.InnerView} - * and a {@link SwapService.SwapStep}, and these views know what - * the previous view before them should be. - */ - 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. */ - @SwapService.SwapStep int getStep(); - - @SwapService.SwapStep int getPreviousStep(); - - @ColorRes int getToolbarColour(); - - String getToolbarTitle(); - } - - private static final String TAG = "SwapWorkflowActivity"; - private static final int CONNECT_TO_SWAP = 1; private static final int REQUEST_BLUETOOTH_ENABLE_FOR_SWAP = 2; private static final int REQUEST_BLUETOOTH_DISCOVERABLE = 3; @@ -116,7 +101,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { private static final int REQUEST_WRITE_SETTINGS_PERMISSION = 5; private Toolbar toolbar; - private InnerView currentView; + private SwapView currentView; private boolean hasPreparedLocalRepo; private PrepareSwapRepo updateSwappableAppsTask; private NewRepoConfig confirmSwapConfig; @@ -165,12 +150,50 @@ public class SwapWorkflowActivity extends AppCompatActivity { @Override public void onBackPressed() { - if (currentView.getStep() == SwapService.STEP_INTRO) { - SwapService.stop(this); + if (currentView.getLayoutResId() == SwapService.STEP_INTRO) { + SwapService.stop(this); // TODO SwapService should always be running, while swap is running finish(); } else { - int nextStep = currentView.getPreviousStep(); - getService().setStep(nextStep); + // TODO: Currently StartSwapView is handleed by the SwapWorkflowActivity as a special case, where + // if getLayoutResId is STEP_INTRO, don't even bother asking for getPreviousStep. But that is a + // bit messy. It would be nicer if this was handled using the same mechanism as everything + // else. + int nextStep = -1; + switch (currentView.getLayoutResId()) { + case R.layout.swap_confirm_receive: + nextStep = SwapService.STEP_INTRO; + break; + case R.layout.swap_connecting: + nextStep = R.layout.swap_select_apps; + break; + case R.layout.swap_initial_loading: + nextStep = R.layout.swap_join_wifi; + break; + case R.layout.swap_join_wifi: + nextStep = SwapService.STEP_INTRO; + break; + case R.layout.swap_nfc: + nextStep = R.layout.swap_join_wifi; + break; + case R.layout.swap_select_apps: + // TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it + // so that it is, or so that this doesn't go back there. + nextStep = getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : R.layout.swap_join_wifi; + break; + case R.layout.swap_send_fdroid: + nextStep = SwapService.STEP_INTRO; + break; + case R.layout.swap_start_swap: + nextStep = SwapService.STEP_INTRO; + break; + case R.layout.swap_success: + nextStep = SwapService.STEP_INTRO; + break; + case R.layout.swap_wifi_qr: + nextStep = R.layout.swap_join_wifi; + break; + } + getService().setCurrentView(nextStep); showRelevantView(); } } @@ -194,7 +217,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { toolbar.setTitleTextAppearance(getApplicationContext(), R.style.SwapTheme_Wizard_Text_Toolbar); setSupportActionBar(toolbar); - container = (ViewGroup) findViewById(R.id.fragment_container); + container = (ViewGroup) findViewById(R.id.container); localBroadcastManager = LocalBroadcastManager.getInstance(this); wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); @@ -211,9 +234,99 @@ public class SwapWorkflowActivity extends AppCompatActivity { @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); - boolean parent = super.onPrepareOptionsMenu(menu); - boolean inner = currentView != null && currentView.buildMenu(menu, getMenuInflater()); - return parent || inner; + + MenuInflater menuInflater = getMenuInflater(); + switch (currentView.getLayoutResId()) { + case R.layout.swap_select_apps: + menuInflater.inflate(R.menu.swap_next_search, menu); + setUpNextButton(menu, R.string.next); + setUpSearchView(menu); + return true; + case R.layout.swap_success: + menuInflater.inflate(R.menu.swap_search, menu); + setUpSearchView(menu); + return true; + case R.layout.swap_join_wifi: + menuInflater.inflate(R.menu.swap_next, menu); + setUpNextButton(menu, R.string.next); + return true; + case R.layout.swap_nfc: + menuInflater.inflate(R.menu.swap_next, menu); + setUpNextButton(menu, R.string.skip); + return true; + } + + return super.onPrepareOptionsMenu(menu); + } + + private void setUpNextButton(Menu menu, @StringRes int titleResId) { + MenuItem next = menu.findItem(R.id.action_next); + CharSequence title = getString(titleResId); + next.setTitle(title); + next.setTitleCondensed(title); + MenuItemCompat.setShowAsAction(next, + MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT); + next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + sendNext(); + return true; + } + }); + } + + void sendNext() { + int currentLayoutResId = currentView.getLayoutResId(); + switch (currentLayoutResId) { + case R.layout.swap_select_apps: + onAppsSelected(); + break; + case R.layout.swap_join_wifi: + inflateSwapView(R.layout.swap_select_apps); + break; + case R.layout.swap_nfc: + inflateSwapView(R.layout.swap_wifi_qr); + break; + } + } + + private void setUpSearchView(Menu menu) { + SearchView searchView = new SearchView(this); + + MenuItem searchMenuItem = menu.findItem(R.id.action_search); + MenuItemCompat.setActionView(searchMenuItem, searchView); + MenuItemCompat.setShowAsAction(searchMenuItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String newText) { + String currentFilterString = currentView.getCurrentFilterString(); + String newFilter = !TextUtils.isEmpty(newText) ? newText : null; + if (currentFilterString == null && newFilter == null) { + return true; + } + if (currentFilterString != null && currentFilterString.equals(newFilter)) { + return true; + } + currentView.setCurrentFilterString(newFilter); + if (currentView instanceof SelectAppsView) { + getSupportLoaderManager().restartLoader(currentView.getLayoutResId(), null, + (SelectAppsView) currentView); + } else if (currentView instanceof SwapSuccessView) { + getSupportLoaderManager().restartLoader(currentView.getLayoutResId(), null, + (SwapSuccessView) currentView); + } else { + throw new IllegalStateException(currentView.getClass() + " does not have Loader!"); + } + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return true; + } + }); } @Override @@ -310,7 +423,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { private void showRelevantView(boolean forceReload) { if (service == null) { - showInitialLoading(); + inflateSwapView(R.layout.swap_initial_loading); return; } @@ -323,62 +436,50 @@ public class SwapWorkflowActivity extends AppCompatActivity { return; } - if (!forceReload && (container.getVisibility() == View.GONE || currentView != null && currentView.getStep() == service.getStep())) { + if (!forceReload && (container.getVisibility() == View.GONE || currentView != null && currentView.getLayoutResId() == service.getCurrentView())) { // Already showing the correct step, so don't bother changing anything. return; } - switch (service.getStep()) { + int currentView = service.getCurrentView(); + switch (currentView) { case SwapService.STEP_INTRO: showIntro(); + return; + case R.layout.swap_nfc: + if (!attemptToShowNfc()) { + inflateSwapView(R.layout.swap_wifi_qr); + return; + } break; - case SwapService.STEP_SELECT_APPS: - showSelectApps(); - break; - case SwapService.STEP_SHOW_NFC: - showNfc(); - break; - case SwapService.STEP_JOIN_WIFI: - showJoinWifi(); - break; - case SwapService.STEP_WIFI_QR: - showWifiQr(); - break; - case SwapService.STEP_SUCCESS: - showSwapConnected(); - break; - case SwapService.STEP_CONNECTING: + case R.layout.swap_connecting: // TODO: Properly decide what to do here (i.e. returning to the activity after it was connecting)... - inflateInnerView(R.layout.swap_blank); - break; + inflateSwapView(R.layout.swap_start_swap); + return; } + inflateSwapView(currentView); } public SwapService getState() { return service; } - private void showNfc() { - if (!attemptToShowNfc()) { - showWifiQr(); - } - } - - private InnerView inflateInnerView(@LayoutRes int viewRes) { + public SwapView inflateSwapView(@LayoutRes int viewRes) { container.removeAllViews(); View view = ((LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false); - currentView = (InnerView) view; + currentView = (SwapView) view; + currentView.setLayoutResId(viewRes); // Don't actually set the step to STEP_INITIAL_LOADING, as we are going to use this view // purely as a placeholder for _whatever view is meant to be shown_. - if (currentView.getStep() != SwapService.STEP_INITIAL_LOADING) { + if (currentView.getLayoutResId() != R.layout.swap_initial_loading) { if (service == null) { throw new IllegalStateException("We are not in the STEP_INITIAL_LOADING state, but the service is not ready."); } - service.setStep(currentView.getStep()); + service.setCurrentView(currentView.getLayoutResId()); } - toolbar.setBackgroundColor(getResources().getColor(currentView.getToolbarColour())); + toolbar.setBackgroundColor(currentView.getToolbarColour()); toolbar.setTitle(currentView.getToolbarTitle()); toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @@ -398,10 +499,6 @@ public class SwapWorkflowActivity extends AppCompatActivity { finish(); } - private void showInitialLoading() { - inflateInnerView(R.layout.swap_initial_loading); - } - public void showIntro() { // If we were previously swapping with a specific client, forget that we were doing that, // as we are starting over now. @@ -414,11 +511,13 @@ public class SwapWorkflowActivity extends AppCompatActivity { } } - inflateInnerView(R.layout.swap_blank); + inflateSwapView(R.layout.swap_start_swap); } private void showConfirmSwap(@NonNull NewRepoConfig config) { - ((ConfirmReceive) inflateInnerView(R.layout.swap_confirm_receive)).setup(config); + ((ConfirmReceiveView) inflateSwapView(R.layout.swap_confirm_receive)).setup(config); + TextView descriptionTextView = (TextView) findViewById(R.id.text_description); + descriptionTextView.setText(getResources().getString(R.string.swap_confirm_connect, config.getHost())); } public void startQrWorkflow() { @@ -435,14 +534,10 @@ public class SwapWorkflowActivity extends AppCompatActivity { }) .create().show(); } else { - showWifiQr(); + inflateSwapView(R.layout.swap_wifi_qr); } } - public void showSelectApps() { - inflateInnerView(R.layout.swap_select_apps); - } - /** * On {@code android-26}, only apps with privileges can access * {@code WRITE_SETTINGS}. So this just shows the tethering settings @@ -471,7 +566,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { if (adapter == null || Build.VERSION.SDK_INT >= 23 // TODO make Bluetooth work with content:// URIs || (!adapter.isEnabled() && getService().getWifiSwap().isConnected())) { - showSendFDroid(); + inflateSwapView(R.layout.swap_send_fdroid); } else { sendFDroidBluetooth(); } @@ -503,8 +598,8 @@ public class SwapWorkflowActivity extends AppCompatActivity { if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) { updateSwappableAppsTask = new PrepareSwapRepo(getService().getAppsToSwap()); updateSwappableAppsTask.execute(); - getService().setStep(SwapService.STEP_CONNECTING); - inflateInnerView(R.layout.swap_connecting); + getService().setCurrentView(R.layout.swap_connecting); + inflateSwapView(R.layout.swap_connecting); } else { onLocalRepoPrepared(); } @@ -513,10 +608,10 @@ public class SwapWorkflowActivity extends AppCompatActivity { /** * Once the UpdateAsyncTask has finished preparing our repository index, we can * 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. + * * 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. */ public void onLocalRepoPrepared() { updateSwappableAppsTask = null; @@ -524,29 +619,13 @@ public class SwapWorkflowActivity extends AppCompatActivity { if (getService().isConnectingWithPeer()) { startSwappingWithPeer(); } else if (!attemptToShowNfc()) { - showWifiQr(); + inflateSwapView(R.layout.swap_wifi_qr); } } private void startSwappingWithPeer() { getService().connectToPeer(); - inflateInnerView(R.layout.swap_connecting); - } - - private void showJoinWifi() { - inflateInnerView(R.layout.swap_join_wifi); - } - - public void showWifiQr() { - inflateInnerView(R.layout.swap_wifi_qr); - } - - public void showSendFDroid() { - inflateInnerView(R.layout.swap_send_fdroid); - } - - public void showSwapConnected() { - inflateInnerView(R.layout.swap_success); + inflateSwapView(R.layout.swap_connecting); } private boolean attemptToShowNfc() { @@ -559,7 +638,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { boolean nfcMessageReady = NfcHelper.setPushMessage(this, Utils.getSharingUri(FDroidApp.repo)); if (Preferences.get().showNfcDuringSwap() && nfcMessageReady) { - inflateInnerView(R.layout.swap_nfc); + inflateSwapView(R.layout.swap_nfc); return true; } return false; @@ -567,20 +646,20 @@ public class SwapWorkflowActivity extends AppCompatActivity { public void swapWith(Peer peer) { getService().swapWith(peer); - showSelectApps(); + inflateSwapView(R.layout.swap_select_apps); } /** * This is for when we initiate a swap by viewing the "Are you sure you want to swap with" view * This can arise either: - * * As a result of scanning a QR code (in which case we likely already have a repo setup) or - * * As a result of the other device selecting our device in the "start swap" screen, in which - * case we are likely just sitting on the start swap screen also, and haven't configured - * anything yet. + * * As a result of scanning a QR code (in which case we likely already have a repo setup) or + * * As a result of the other device selecting our device in the "start swap" screen, in which + * case we are likely just sitting on the start swap screen also, and haven't configured + * anything yet. */ public void swapWith(NewRepoConfig repoConfig) { Peer peer = repoConfig.toPeer(); - if (getService().getStep() == SwapService.STEP_INTRO || getService().getStep() == SwapService.STEP_CONFIRM_SWAP) { + if (getService().getCurrentView() == SwapService.STEP_INTRO || getService().getCurrentView() == R.layout.swap_confirm_receive) { // This will force the "Select apps to swap" workflow to begin. // TODO: Find a better way to decide whether we need to select the apps. Not sure if we // can or cannot be in STEP_INTRO with a full blown repo ready to swap. @@ -784,15 +863,14 @@ public class SwapWorkflowActivity extends AppCompatActivity { * the harder it becomes to reason about and debug the whole thing. Thus,this class * will periodically dump the state to logcat so that it is easier to see when certain * protocols are enabled/disabled. - * + *

* To view only this output from logcat: - * - * adb logcat | grep 'Swap Status' - * + *

+ * adb logcat | grep 'Swap Status' + *

* To exclude this output from logcat (it is very noisy): - * - * adb logcat | grep -v 'Swap Status' - * + *

+ * adb logcat | grep -v 'Swap Status' */ class SwapDebug { @@ -826,11 +904,11 @@ public class SwapWorkflowActivity extends AppCompatActivity { Utils.debugLog("Swap Status", now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + " " + message); new Timer().schedule(new TimerTask() { - @Override - public void run() { - new SwapDebug().logStatus(); - } - }, 1000 + @Override + public void run() { + new SwapDebug().logStatus(); + } + }, 1000 ); } } diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/WifiQrView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/WifiQrView.java index ab55abd2c..ad8fadbba 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/WifiQrView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/WifiQrView.java @@ -7,31 +7,26 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.LightingColorFilter; import android.net.Uri; -import android.support.annotation.ColorRes; -import android.support.annotation.NonNull; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.AttributeSet; -import android.view.Menu; -import android.view.MenuInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; -import android.widget.ScrollView; import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; 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.SwapService; +import org.fdroid.fdroid.localrepo.SwapView; import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker; import java.util.Locale; import java.util.Set; -public class WifiQrView extends ScrollView implements SwapWorkflowActivity.InnerView { +public class WifiQrView extends SwapView { private static final String TAG = "WifiQrView"; @@ -52,10 +47,6 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner super(context, attrs, defStyleAttr, defStyleRes); } - private SwapWorkflowActivity getActivity() { - return (SwapWorkflowActivity) getContext(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -98,32 +89,6 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onWifiStateChanged); } - @Override - public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) { - return false; - } - - @Override - public int getStep() { - return SwapService.STEP_WIFI_QR; - } - - @Override - public int getPreviousStep() { - // TODO: Find a way to make this optionally go back to the NFC screen if appropriate. - return SwapService.STEP_JOIN_WIFI; - } - - @ColorRes - public int getToolbarColour() { - return R.color.swap_blue; - } - - @Override - public String getToolbarTitle() { - return getResources().getString(R.string.swap_scan_qr); - } - private void setUIFromWifi() { if (TextUtils.isEmpty(FDroidApp.repo.address)) { diff --git a/app/src/full/res/layout-sw480dp/start_swap_header.xml b/app/src/full/res/layout-sw480dp/start_swap_header.xml index a3163d65f..049c2d4fe 100644 --- a/app/src/full/res/layout-sw480dp/start_swap_header.xml +++ b/app/src/full/res/layout-sw480dp/start_swap_header.xml @@ -1,32 +1,33 @@ - + + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerCrop" + android:src="@drawable/swap_start_header"/> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_alignParentBottom="true" + android:padding="20dp" + android:paddingLeft="30dp" + android:paddingRight="30dp" + android:paddingEnd="30dp" + android:gravity="center" + android:textAlignment="center" + android:text="@string/swap_intro" + android:textColor="@android:color/white" + android:textSize="18sp" + tools:ignore="UnusedAttribute"/> \ No newline at end of file diff --git a/app/src/full/res/layout/start_swap_header.xml b/app/src/full/res/layout/start_swap_header.xml index 2f8a78fdc..296f97286 100644 --- a/app/src/full/res/layout/start_swap_header.xml +++ b/app/src/full/res/layout/start_swap_header.xml @@ -1,7 +1,8 @@ - + \ No newline at end of file diff --git a/app/src/full/res/layout/swap_activity.xml b/app/src/full/res/layout/swap_activity.xml index 8bda77a4c..6d25e3a3d 100644 --- a/app/src/full/res/layout/swap_activity.xml +++ b/app/src/full/res/layout/swap_activity.xml @@ -5,20 +5,20 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> - + + android:id="@+id/toolbar" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:titleTextAppearance="@style/SwapTheme.Wizard.Text" + titleTextAppearance="@style/SwapTheme.Wizard.Text" + android:minHeight="?attr/actionBarSize" + android:background="?attr/colorPrimary" + tools:ignore="UnusedAttribute"/> + android:id="@+id/container" + android:layout_width="fill_parent" + android:layout_height="fill_parent"/> \ No newline at end of file diff --git a/app/src/full/res/layout/swap_app_list_item.xml b/app/src/full/res/layout/swap_app_list_item.xml index 84aedf51c..cbe716ff7 100644 --- a/app/src/full/res/layout/swap_app_list_item.xml +++ b/app/src/full/res/layout/swap_app_list_item.xml @@ -1,96 +1,96 @@ + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:paddingBottom="2dip" + android:paddingTop="2dip"> + android:id="@android:id/icon" + android:layout_width="48dip" + android:layout_height="48dip" + android:layout_marginStart="?android:attr/listPreferredItemPaddingStart" + android:layout_marginLeft="10dp" + android:layout_marginTop="6dip" + android:layout_alignParentStart="true" + android:layout_alignParentLeft="true" + tools:src="@drawable/ic_launcher"/> + android:id="@+id/button_or_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerInParent="true" + android:orientation="vertical" + android:gravity="end" + android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd" + android:layout_marginRight="10dp">