BobStore/src/org/fdroid/fdroid/views/LocalRepoActivity.java
Hans-Christoph Steiner 107eab5eac Local Repo webserver turns itself off if it was automatically started
When you visit LocalRepoActivity, the swapping webserver is automatically
turned on, since it is required for any swapping to happen.  When it was
automatically turned on, it will automatically turn itself off after 15
minutes to make sure that it doesn't stay running forever.  If the user
manually turns it off, that cancels the automatic stop.
2014-05-08 00:58:42 -04:00

331 lines
12 KiB
Java

package org.fdroid.fdroid.views;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.*;
import android.content.res.Configuration;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.*;
import android.widget.*;
import org.fdroid.fdroid.*;
import org.fdroid.fdroid.localrepo.LocalRepoService;
import org.fdroid.fdroid.net.WifiStateChangeService;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
public class LocalRepoActivity extends Activity {
private static final String TAG = "LocalRepoActivity";
private ProgressDialog repoProgress;
private WifiManager wifiManager;
private Button enableWifiButton;
private CheckBox repoSwitch;
private Timer stopTimer;
private int SET_IP_ADDRESS = 7345;
private int UPDATE_REPO = 7346;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((FDroidApp) getApplication()).applyTheme(this);
setContentView(R.layout.local_repo_activity);
enableWifiButton = (Button) findViewById(R.id.enable_wifi);
repoSwitch = (CheckBox) findViewById(R.id.repoSwitch);
wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
}
@Override
public void onResume() {
super.onResume();
resetNetworkInfo();
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange,
new IntentFilter(WifiStateChangeService.BROADCAST));
LocalBroadcastManager.getInstance(this).registerReceiver(onLocalRepoChange,
new IntentFilter(LocalRepoService.STATE));
// if no local repo exists, create one with only FDroid in it
if (!FDroidApp.localRepo.xmlIndex.exists())
new UpdateAsyncTask(this, new String[] {
getPackageName(),
}).execute();
// start repo by default
FDroidApp.startLocalRepoService(LocalRepoActivity.this);
// automatically turn off after 15 minutes
stopTimer = new Timer();
stopTimer.schedule(new TimerTask() {
@Override
public void run() {
FDroidApp.stopLocalRepoService(LocalRepoActivity.this);
}
}, 900000); // 15 minutes
}
@Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
LocalBroadcastManager.getInstance(this).unregisterReceiver(onLocalRepoChange);
}
private BroadcastReceiver onWifiChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent i) {
resetNetworkInfo();
}
};
private BroadcastReceiver onLocalRepoChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent i) {
String state = i.getStringExtra(LocalRepoService.STATE);
if (state != null && state.equals(LocalRepoService.STARTED))
setRepoSwitchChecked(true);
else
setRepoSwitchChecked(false);
}
};
private void resetNetworkInfo() {
int wifiState = wifiManager.getWifiState();
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
setUIFromWifi();
wireRepoSwitchToWebServer();
repoSwitch.setVisibility(View.VISIBLE);
enableWifiButton.setVisibility(View.GONE);
} else {
repoSwitch.setChecked(false);
repoSwitch.setVisibility(View.GONE);
enableWifiButton.setVisibility(View.VISIBLE);
enableWifiButton.setText(R.string.enable_wifi);
enableWifiButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
enableWifiButton.setText(R.string.enabling_wifi);
wifiManager.setWifiEnabled(true);
/*
* Once the wifi is connected to a network, then
* WifiStateChangeReceiver will receive notice, and kick off
* the process of getting the info about the wifi
* connection.
*/
}
});
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.local_repo_activity, menu);
if (Build.VERSION.SDK_INT < 11) // TODO remove after including appcompat-v7
menu.findItem(R.id.menu_setup_repo).setVisible(false);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_setup_repo:
startActivityForResult(new Intent(this, SelectLocalAppsActivity.class), UPDATE_REPO);
return true;
case R.id.menu_send_fdroid_via_wifi:
startActivity(new Intent(this, QrWizardWifiNetworkActivity.class));
return true;
case R.id.menu_settings:
startActivityForResult(new Intent(this, PreferencesActivity.class), SET_IP_ADDRESS);
return true;
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK)
return;
if (requestCode == SET_IP_ADDRESS) {
setUIFromWifi();
} else if (requestCode == UPDATE_REPO) {
setUIFromWifi();
new UpdateAsyncTask(this, FDroidApp.selectedApps.toArray(new String[0]))
.execute();
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case 0:
repoProgress = new ProgressDialog(this);
repoProgress.setMessage("Scanning Apps. Please wait...");
repoProgress.setIndeterminate(false);
repoProgress.setMax(100);
repoProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
repoProgress.setCancelable(false);
repoProgress.show();
return repoProgress;
default:
return null;
}
}
private void wireRepoSwitchToWebServer() {
repoSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setRepoSwitchChecked(repoSwitch.isChecked());
if (repoSwitch.isChecked()) {
FDroidApp.startLocalRepoService(LocalRepoActivity.this);
} else {
FDroidApp.stopLocalRepoService(LocalRepoActivity.this);
stopTimer.cancel(); // disable automatic stop
}
}
});
}
private void setRepoSwitchChecked(boolean checked) {
repoSwitch.setChecked(checked);
if (checked) {
repoSwitch.setText(R.string.local_repo_running);
} else {
repoSwitch.setText(R.string.touch_to_turn_on_local_repo);
}
}
@TargetApi(14)
private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address))
return;
// the fingerprint is not useful on the button label
String buttonLabel = FDroidApp.repo.address.replaceAll("\\?.*$", "");
TextView sharingUriTextView = (TextView) findViewById(R.id.sharing_uri);
sharingUriTextView.setText(buttonLabel);
/*
* Set URL to UPPER for compact QR Code, FDroid will translate it back.
* Remove the SSID from the query string since SSIDs are case-sensitive.
* Instead the receiver will have to rely on the BSSID to find the right
* wifi AP to join. Lots of QR Scanners are buggy and do not respect
* custom URI schemes, so we have to use http:// or https:// :-(
*/
final String qrUriString = Utils.getSharingUri(this, FDroidApp.repo).toString()
.replaceFirst("fdroidrepo", "http")
.replaceAll("ssid=[^?]*", "")
.toUpperCase(Locale.ENGLISH);
Log.i("QRURI", qrUriString);
if (Build.VERSION.SDK_INT >= 8) // zxing requires >= 8
new QrGenAsyncTask(this, R.id.repoQrCode).execute(qrUriString);
TextView wifiNetworkNameTextView = (TextView) findViewById(R.id.wifi_network);
wifiNetworkNameTextView.setText(FDroidApp.ssid);
TextView fingerprintTextView = (TextView) findViewById(R.id.fingerprint);
if (FDroidApp.repo.fingerprint != null) {
fingerprintTextView.setVisibility(View.VISIBLE);
fingerprintTextView.setText(FDroidApp.repo.fingerprint);
} else {
fingerprintTextView.setVisibility(View.GONE);
}
// the required NFC API was added in 4.0 aka Ice Cream Sandwich
if (Build.VERSION.SDK_INT >= 14) {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null)
return;
nfcAdapter.setNdefPushMessage(new NdefMessage(new NdefRecord[] {
NdefRecord.createUri(Utils.getSharingUri(this, FDroidApp.repo)),
}), this);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// ignore orientation/keyboard change
super.onConfigurationChanged(newConfig);
}
class UpdateAsyncTask extends AsyncTask<Void, String, Void> {
private static final String TAG = "UpdateAsyncTask";
private ProgressDialog progressDialog;
private String[] selectedApps;
private Uri sharingUri;
public UpdateAsyncTask(Context c, String[] apps) {
selectedApps = apps;
progressDialog = new ProgressDialog(c);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle(R.string.updating);
sharingUri = Utils.getSharingUri(c, FDroidApp.repo);
}
@Override
protected void onPreExecute() {
progressDialog.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
publishProgress(getString(R.string.deleting_repo));
FDroidApp.localRepo.deleteRepo();
for (String app : selectedApps) {
publishProgress(String.format(getString(R.string.adding_apks_format), app));
FDroidApp.localRepo.addApp(getApplicationContext(), app);
}
FDroidApp.localRepo.writeIndexPage(sharingUri.toString());
publishProgress(getString(R.string.writing_index_xml));
FDroidApp.localRepo.writeIndexXML();
publishProgress(getString(R.string.linking_apks));
FDroidApp.localRepo.copyApksToRepo();
publishProgress(getString(R.string.copying_icons));
// run the icon copy without progress, its not a blocker
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
FDroidApp.localRepo.copyIconsToRepo();
return null;
}
}.execute();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(String... progress) {
super.onProgressUpdate(progress);
progressDialog.setMessage(progress[0]);
}
@Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
Toast.makeText(getBaseContext(), R.string.updated_local_repo, Toast.LENGTH_SHORT)
.show();
}
}
}