rework swap startup putting SwapService first

SwapService is the thing that needs to be always running, and the last
thing killed.  So it should start first, and stop last.  So now, the user
clicking the button starts SwapService, which starts SwapWorkflowActivity.
This also eliminatings the "Loading" screen in favor of just showing the
StartSwapView with various inline progress indicators.
This commit is contained in:
Hans-Christoph Steiner 2019-05-16 14:07:00 +02:00
parent 035a89e5f6
commit d91fbe7b0e
6 changed files with 36 additions and 93 deletions

View File

@ -14,6 +14,7 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -72,10 +73,20 @@ public class SwapService extends Service {
@NonNull
private final Set<String> appsToSwap = new HashSet<>();
private static LocalBroadcastManager localBroadcastManager;
private static SharedPreferences swapPreferences;
private static BluetoothAdapter bluetoothAdapter;
private static WifiManager wifiManager;
public static void start(Context context) {
Intent intent = new Intent(context, SwapService.class);
if (Build.VERSION.SDK_INT < 26) {
context.startService(intent);
} else {
context.startForegroundService(intent);
}
}
public static void stop(Context context) {
Intent intent = new Intent(context, SwapService.class);
context.stopService(intent);
@ -413,12 +424,8 @@ public class SwapService extends Service {
public void onCreate() {
super.onCreate();
Utils.debugLog(TAG, "Creating swap service.");
startForeground(NOTIFICATION, createNotification());
deleteAllSwapRepos();
localBroadcastManager = LocalBroadcastManager.getInstance(this);
swapPreferences = getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@ -455,9 +462,16 @@ public class SwapService extends Service {
}
}
/**
* This is for setting things up for when the {@code SwapService} was
* started by the user clicking on the initial start button. The things
* that must be run always on start-up go in {@link #onCreate()}.
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
deleteAllSwapRepos();
startActivity(new Intent(this, SwapWorkflowActivity.class));
return START_NOT_STICKY;
}
@Override
@ -525,7 +539,6 @@ public class SwapService extends Service {
}
private void initTimer() {
// TODO replace by Android scheduler
if (timer != null) {
Utils.debugLog(TAG, "Cancelling existing timeout timer so timeout can be reset.");
timer.cancel();
@ -537,6 +550,8 @@ public class SwapService extends Service {
@Override
public void run() {
Utils.debugLog(TAG, "Disabling swap because " + TIMEOUT + "ms passed.");
String msg = getString(R.string.swap_toast_closing_nearby_after_timeout);
Utils.showToastFromService(SwapService.this, msg, android.widget.Toast.LENGTH_LONG);
stop(SwapService.this);
}
}, TIMEOUT);

View File

@ -21,7 +21,7 @@ public class SwapView extends RelativeLayout {
public final int toolbarColor;
public final String toolbarTitle;
private int layoutResId;
private int layoutResId = -1;
protected String currentFilterString;

View File

@ -18,8 +18,8 @@ import android.widget.TextView;
import android.widget.Toast;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SDCardScannerService;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.TreeUriScannerIntentService;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
import java.io.File;
@ -75,7 +75,7 @@ class NearbyViewBinder {
ActivityCompat.requestPermissions(activity, new String[]{coarseLocation},
MainActivity.REQUEST_LOCATION_PERMISSIONS);
} else {
activity.startActivity(new Intent(activity, SwapWorkflowActivity.class));
SwapService.start(activity);
}
}
});

View File

@ -102,7 +102,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private ViewGroup container;
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;
private static final int REQUEST_BLUETOOTH_ENABLE_FOR_SEND = 4;
@ -134,17 +133,14 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Utils.debugLog(TAG, "Swap service connected. Will hold onto it so we can talk to it regularly.");
service = ((SwapService.Binder) binder).getService();
showRelevantView();
}
// TODO: What causes this? Do we need to stop swapping explicitly when this is invoked?
@Override
public void onServiceDisconnected(ComponentName className) {
Utils.debugLog(TAG, "Swap service disconnected");
finish();
service = null;
// TODO: What to do about the UI in this instance?
}
};
@ -153,10 +149,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
@NonNull
public SwapService getService() {
if (service == null) {
// *Slightly* more informative than a null-pointer error that would otherwise happen.
throw new IllegalStateException("Trying to access swap service before it was initialized.");
}
return service;
}
@ -178,9 +170,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
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 = STEP_INTRO;
break;
@ -215,12 +204,12 @@ public class SwapWorkflowActivity extends AppCompatActivity {
((FDroidApp) getApplication()).setSecureWindow(this);
super.onCreate(savedInstanceState);
// The server should not be doing anything or occupying any (noticeable) resources
// until we actually ask it to enable swapping. Therefore, we will start it nice and
// early so we don't have to wait until it is connected later.
Intent service = new Intent(this, SwapService.class);
if (bindService(service, serviceConnection, Context.BIND_AUTO_CREATE)) {
startService(service);
currentView = new SwapView(this); // dummy placeholder to avoid NullPointerExceptions;
if (!bindService(new Intent(this, SwapService.class), serviceConnection,
BIND_ABOVE_CLIENT | BIND_IMPORTANT)) {
Toast.makeText(this, "ERROR: cannot bind to SwapService!", Toast.LENGTH_LONG).show();
finish();
}
setContentView(R.layout.swap_activity);
@ -357,7 +346,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
new IntentFilter(UpdateService.LOCAL_ACTION_STATUS));
checkIncomingIntent();
showRelevantView();
}
@Override
@ -446,15 +434,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
private void showRelevantView() {
showRelevantView(false);
}
private void showRelevantView(boolean forceReload) {
if (service == null) {
inflateSwapView(R.layout.swap_initial_loading);
return;
}
if (confirmSwapConfig != null) {
inflateSwapView(R.layout.swap_confirm_receive);
@ -463,12 +442,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
return;
}
if (!forceReload
&& (container.getVisibility() == View.GONE || currentView != null && currentView.getLayoutResId() == currentSwapViewLayoutRes)) {
// Already showing the correct step, so don't bother changing anything.
return;
}
switch (currentSwapViewLayoutRes) {
case STEP_INTRO:
showIntro();
@ -491,20 +464,12 @@ public class SwapWorkflowActivity extends AppCompatActivity {
return service;
}
public SwapView inflateSwapView(@LayoutRes int viewRes) {
public void inflateSwapView(@LayoutRes int viewRes) {
container.removeAllViews();
View view = ((LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false);
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.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.");
}
currentSwapViewLayoutRes = currentView.getLayoutResId();
}
currentSwapViewLayoutRes = viewRes;
toolbar.setBackgroundColor(currentView.getToolbarColour());
toolbar.setTitle(currentView.getToolbarTitle());
@ -534,8 +499,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
setUpConnectingView();
break;
}
return currentView;
}
private void onToolbarCancel() {
@ -734,8 +697,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
Toast.makeText(this, R.string.swap_qr_isnt_for_swap, Toast.LENGTH_SHORT).show();
}
}
} else if (requestCode == CONNECT_TO_SWAP && resultCode == Activity.RESULT_OK) {
finish();
} else if (requestCode == REQUEST_WRITE_SETTINGS_PERMISSION) {
if (Build.VERSION.SDK_INT >= 23 && Settings.System.canWrite(this)) {
setupWifiAP();
@ -809,11 +770,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, discoverableTimeout);
startActivityForResult(intent, REQUEST_BLUETOOTH_DISCOVERABLE);
}
if (service == null) {
throw new IllegalStateException("Can't start Bluetooth swap because service is null for some strange reason.");
}
service.getBluetoothSwap().startInBackground(); // TODO replace with Intent to SwapService
}
@ -897,7 +853,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
case Installer.ACTION_INSTALL_COMPLETE:
localBroadcastManager.unregisterReceiver(this);
showRelevantView(true);
showRelevantView();
break;
case Installer.ACTION_INSTALL_INTERRUPTED:
localBroadcastManager.unregisterReceiver(this);

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fdroid.fdroid.localrepo.SwapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/swap_blue"
android:paddingTop="38.8dp"> <!-- 69px * 96dpi / 160dpi -->
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/loading"
android:textSize="18sp"
android:layout_below="@+id/progress"
android:textColor="@android:color/white"
android:layout_centerHorizontal="true"/>
</org.fdroid.fdroid.localrepo.SwapView>

View File

@ -517,6 +517,7 @@ This often occurs with apps installed via Google Play or other sources, if they
<string name="swap_toast_invalid_url">Invalid URL for swapping: %1$s</string>
<string name="swap_toast_hotspot_enabled">Wi-Fi Hotspot enabled</string>
<string name="swap_toast_could_not_enable_hotspot">Could not enable Wi-Fi Hotspot!</string>
<string name="swap_toast_closing_nearby_after_timeout">Nearby closed since it was idle.</string>
<string name="install_confirm">needs access to</string>
<string name="install_confirm_update">Do you want to install an update