From e53a56f7b20264504776ad6b27a66ee68be3d299 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 16 Aug 2015 23:32:37 +1000 Subject: [PATCH] Show "preparing local repo" stuff in activity, not dialog. Use the same view as when downloading a swap index. This means no more progress dialogs, and no more Toasts when finished, which is good. --- .../fdroid/fdroid/localrepo/SwapService.java | 9 +- .../fdroid/views/swap/SwapConnecting.java | 144 ++++++++++++------ .../views/swap/SwapWorkflowActivity.java | 82 +++++----- 3 files changed, 140 insertions(+), 95 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java index c413abda1..a5e68852b 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java @@ -62,7 +62,7 @@ import java.util.TimerTask; * the future. * * TODO: Show "Waiting for other device to finish setting up swap" when only F-Droid shown in swap - * TODO: Handle not connected to wifi more gracefully. For example, Bonjour discovery falls over. + * TODO: Handle "not connected to wifi" more gracefully. For example, Bonjour discovery falls over. * TODO: Remove peers from list of peers when no longer "visible". * TODO: Feedback for "Setting up (wifi|bluetooth)" in start swap view is not as immediate as I had hoped. * TODO: Turn off bluetooth after cancelling/timing out if we turned it on. @@ -162,6 +162,13 @@ public class SwapService extends Service { } } + public void connectToPeer() { + if (getPeer() == null) { + throw new IllegalStateException("Cannot connect to peer, no peer has been selected."); + } + connectTo(getPeer(), getPeer().shouldPromptForSwapBack()); + } + public void connectTo(@NonNull Peer peer, boolean requestSwapBack) { if (peer != this.peer) { Log.e(TAG, "Oops, got a different peer to swap with than initially planned."); diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java index 2df1356a6..844a2bd8f 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java @@ -49,26 +49,11 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity return (SwapWorkflowActivity)getContext(); } - private SwapService 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, peer.getName()); - ((TextView) findViewById(R.id.heading)).setText(heading); - + ((TextView) findViewById(R.id.heading)).setText(R.string.swap_connecting); findViewById(R.id.back).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -77,56 +62,119 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity }); // TODO: Unregister correctly, not just when being notified of completion or errors. - LocalBroadcastManager.getInstance(getActivity()).registerReceiver(repoUpdateReceiver, new IntentFilter(UpdateService.LOCAL_ACTION_STATUS)); - getManager().connectTo(peer, peer.shouldPromptForSwapBack()); + LocalBroadcastManager.getInstance(getActivity()).registerReceiver( + repoUpdateReceiver, new IntentFilter(UpdateService.LOCAL_ACTION_STATUS)); + LocalBroadcastManager.getInstance(getActivity()).registerReceiver( + prepareSwapReceiver, new IntentFilter(SwapWorkflowActivity.PrepareSwapRepo.ACTION)); + } + + private BroadcastReceiver repoUpdateReceiver = new ConnectSwapReceiver(); + private BroadcastReceiver prepareSwapReceiver = new PrepareSwapReceiver(); + + /** + * 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. + */ + class PrepareSwapReceiver extends Receiver { + + @Override + protected String getMessageExtra() { + return SwapWorkflowActivity.PrepareSwapRepo.EXTRA_MESSAGE; + } + + protected int getType(Intent intent) { + return intent.getIntExtra(SwapWorkflowActivity.PrepareSwapRepo.EXTRA_TYPE, -1); + } + + @Override + protected boolean isComplete(Intent intent) { + return getType(intent) == SwapWorkflowActivity.PrepareSwapRepo.TYPE_COMPLETE; + } + + @Override + protected boolean isError(Intent intent) { + return getType(intent) == SwapWorkflowActivity.PrepareSwapRepo.TYPE_ERROR; + } + + @Override + protected void onComplete() { + getActivity().onLocalRepoPrepared(); + } + } + + /** + * Listens for feedback about a repo update process taking place. + * * Tracks an index.jar download and show the progress messages + */ + class ConnectSwapReceiver extends Receiver { + + @Override + protected String getMessageExtra() { + return UpdateService.EXTRA_MESSAGE; + } + + protected int getStatusCode(Intent intent) { + return intent.getIntExtra(UpdateService.EXTRA_STATUS_CODE, -1); + } + + @Override + protected boolean isComplete(Intent intent) { + int status = getStatusCode(intent); + return status == UpdateService.STATUS_COMPLETE_AND_SAME || + status == UpdateService.STATUS_COMPLETE_WITH_CHANGES; + } + @Override + protected boolean isError(Intent intent) { + int status = getStatusCode(intent); + return status == UpdateService.STATUS_ERROR_GLOBAL || + status == UpdateService.STATUS_ERROR_LOCAL || + status == UpdateService.STATUS_ERROR_LOCAL_SMALL; + } + + @Override + protected void onComplete() { + getActivity().showSwapConnected(); + } } - private BroadcastReceiver repoUpdateReceiver = new BroadcastReceiver() { + abstract class Receiver extends BroadcastReceiver { + + protected abstract String getMessageExtra(); + protected abstract boolean isComplete(Intent intent); + protected abstract boolean isError(Intent intent); + protected abstract void onComplete(); + @Override public void onReceive(Context context, Intent intent) { - int statusCode = intent.getIntExtra(UpdateService.EXTRA_STATUS_CODE, -1); - TextView progressText = ((TextView) findViewById(R.id.heading)); TextView errorText = ((TextView) findViewById(R.id.error)); Button backButton = ((Button) findViewById(R.id.back)); - if (intent.hasExtra(UpdateService.EXTRA_MESSAGE)) { - progressText.setText(intent.getStringExtra(UpdateService.EXTRA_MESSAGE)); + String message = null; + if (intent.hasExtra(getMessageExtra())) { + message = intent.getStringExtra(getMessageExtra()); + if (message != null) { + progressText.setText(message); + } } - boolean finished = false; - boolean error = false; - progressText.setVisibility(View.VISIBLE); errorText.setVisibility(View.GONE); backButton.setVisibility(View.GONE); - switch (statusCode) { - case UpdateService.STATUS_ERROR_GLOBAL: - finished = true; - error = true; - break; - case UpdateService.STATUS_COMPLETE_WITH_CHANGES: - finished = true; - break; - case UpdateService.STATUS_COMPLETE_AND_SAME: - finished = true; - break; - case UpdateService.STATUS_INFO: - break; + if (isError(intent)) { + progressText.setVisibility(View.GONE); + errorText.setVisibility(View.VISIBLE); + backButton.setVisibility(View.VISIBLE); + return; } - if (finished) { - LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(repoUpdateReceiver); - if (error) { - progressText.setVisibility(View.GONE); - errorText.setVisibility(View.VISIBLE); - backButton.setVisibility(View.VISIBLE); - } else { - getActivity().showSwapConnected(); - } + if (isComplete(intent)) { + onComplete(); } } }; 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 dd37ea9ac..943d4e86a 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -16,6 +16,7 @@ import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NavUtils; +import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -261,7 +262,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { showSwapConnected(); break; case SwapService.STEP_CONNECTING: - // TODO: Properly decide what to do here... + // TODO: Properly decide what to do here (i.e. returning to the activity after it was connecting)... inflateInnerView(R.layout.swap_blank); break; } @@ -345,8 +346,10 @@ public class SwapWorkflowActivity extends AppCompatActivity { // Otherwise, probably will need to scan the file system. public void onAppsSelected() { if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) { - updateSwappableAppsTask = new PrepareFullSwapRepo(getService().getAppsToSwap()); + updateSwappableAppsTask = new PrepareSwapRepo(getService().getAppsToSwap()); updateSwappableAppsTask.execute(); + getService().setStep(SwapService.STEP_CONNECTING); + inflateInnerView(R.layout.swap_connecting); } else { onLocalRepoPrepared(); } @@ -370,7 +373,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { * * 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() { + public void onLocalRepoPrepared() { updateSwappableAppsTask = null; hasPreparedLocalRepo = true; if (getService().isConnectingWithPeer()) { @@ -381,6 +384,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { } private void startSwappingWithPeer() { + getService().connectToPeer(); inflateInnerView(R.layout.swap_connecting); } @@ -542,39 +546,14 @@ public class SwapWorkflowActivity extends AppCompatActivity { } } - class PrepareFullSwapRepo extends PrepareSwapRepo { + class PrepareSwapRepo extends AsyncTask { - @NonNull - private final ProgressDialog progressDialog; - - public PrepareFullSwapRepo(@NonNull Set apps) { - super(apps); - progressDialog = new ProgressDialog(context); - progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); - progressDialog.setTitle(R.string.updating); - } - - @Override - protected void onPreExecute() { - progressDialog.show(); - } - - @Override - protected void onProgressUpdate(String... progress) { - super.onProgressUpdate(progress); - progressDialog.setMessage(progress[0]); - } - - @Override - protected void onPostExecute(Void result) { - progressDialog.dismiss(); - Toast.makeText(context, R.string.updated_local_repo, Toast.LENGTH_SHORT).show(); - onLocalRepoPrepared(); - } - - } - - abstract class PrepareSwapRepo extends AsyncTask { + public static final String ACTION = "PrepareSwapRepo.Action"; + public static final String EXTRA_MESSAGE = "PrepareSwapRepo.Status.Message"; + public static final String EXTRA_TYPE = "PrepareSwapRepo.Action.Type"; + public static final int TYPE_STATUS = 0; + public static final int TYPE_COMPLETE = 1; + public static final int TYPE_ERROR = 2; @SuppressWarnings("UnusedDeclaration") private static final String TAG = "UpdateAsyncTask"; @@ -594,22 +573,36 @@ public class SwapWorkflowActivity extends AppCompatActivity { sharingUri = Utils.getSharingUri(FDroidApp.repo); } + private void broadcast(int type) { + broadcast(type, null); + } + + private void broadcast(int type, String message) { + Intent intent = new Intent(ACTION); + intent.putExtra(EXTRA_TYPE, type); + if (message != null) { + Log.d(TAG, "Preparing swap: " + message); + intent.putExtra(EXTRA_MESSAGE, message); + } + LocalBroadcastManager.getInstance(SwapWorkflowActivity.this).sendBroadcast(intent); + } + @Override protected Void doInBackground(Void... params) { try { final LocalRepoManager lrm = LocalRepoManager.get(context); - publishProgress(getString(R.string.deleting_repo)); + broadcast(TYPE_STATUS, getString(R.string.deleting_repo)); lrm.deleteRepo(); for (String app : selectedApps) { - publishProgress(String.format(getString(R.string.adding_apks_format), app)); + broadcast(TYPE_STATUS, String.format(getString(R.string.adding_apks_format), app)); lrm.addApp(context, app); } lrm.writeIndexPage(sharingUri.toString()); - publishProgress(getString(R.string.writing_index_jar)); + broadcast(TYPE_STATUS, getString(R.string.writing_index_jar)); lrm.writeIndexJar(); - publishProgress(getString(R.string.linking_apks)); + broadcast(TYPE_STATUS, getString(R.string.linking_apks)); lrm.copyApksToRepo(); - publishProgress(getString(R.string.copying_icons)); + broadcast(TYPE_STATUS, getString(R.string.copying_icons)); // run the icon copy without progress, its not a blocker // TODO: Fix lint error about this being run from a worker thread, says it should be // run on a main thread. @@ -621,17 +614,14 @@ public class SwapWorkflowActivity extends AppCompatActivity { return null; } }.execute(); + + broadcast(TYPE_COMPLETE); } catch (Exception e) { + broadcast(TYPE_ERROR); e.printStackTrace(); } return null; } - - @Override - protected void onProgressUpdate(String... progress) { - super.onProgressUpdate(progress); - Log.d(TAG, progress[0]); - } } /**