BobStore/src/org/fdroid/fdroid/views/LocalRepoActivity.java
Hans-Christoph Steiner 882e010052 create initial repo with only FDroid in it
This automatically creates a repo with only FDroid in it the first time the
user goes to the Local Repo view.  Having an empty repo is useless if the
user is trying to swap with someone.  Having FDroid in there is not a
privacy leak since FDroid is needed for the swap process, and it will then
enable people to automatically get updates from each other, and do the
bootstrap process from the web browser.

fixes #2954 https://dev.guardianproject.info/issues/2954
2014-05-06 19:51:15 -04:00

284 lines
10 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.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import org.fdroid.fdroid.*;
import org.fdroid.fdroid.net.WifiStateChangeService;
import java.util.Locale;
public class LocalRepoActivity extends Activity {
private static final String TAG = "LocalRepoActivity";
private ProgressDialog repoProgress;
private WifiManager wifiManager;
private ToggleButton repoSwitch;
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);
setContentView(R.layout.local_repo_activity);
repoSwitch = (ToggleButton) 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));
// if no local repo exists, create one with only FDroid in it
if (!FDroidApp.localRepo.xmlIndex.exists())
new UpdateAsyncTask(this, new String[] {
getPackageName(),
}).execute();
}
@Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
}
private BroadcastReceiver onWifiChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent i) {
resetNetworkInfo();
}
};
private void resetNetworkInfo() {
int wifiState = wifiManager.getWifiState();
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
setUIFromWifi();
wireRepoSwitchToWebServer();
} else {
repoSwitch.setChecked(false);
repoSwitch.setText(R.string.enable_wifi);
repoSwitch.setTextOn(getString(R.string.enabling_wifi));
repoSwitch.setTextOff(getString(R.string.enable_wifi));
repoSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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) {
if (repoSwitch.isChecked()) {
FDroidApp.startLocalRepoService(LocalRepoActivity.this);
} else {
FDroidApp.stopLocalRepoService(LocalRepoActivity.this);
}
}
});
}
@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("\\?.*$", "");
repoSwitch.setText(buttonLabel);
repoSwitch.setTextOn(buttonLabel);
repoSwitch.setTextOff(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);
new QrGenAsyncTask(this, R.id.repoQrCode).execute(qrUriString);
TextView wifiNetworkNameTextView = (TextView) findViewById(R.id.wifiNetworkName);
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();
}
}
}