예제 #1
0
  private void bindBrowser(WebView appView) {
    gap = new Device(appView, this);
    accel = new AccelBroker(appView, this);
    launcher = new CameraLauncher(appView, this);
    mContacts = new ContactManager(appView, this);
    fs = new FileUtils(appView);
    netMan = new NetworkManager(appView, this);
    mCompass = new CompassListener(appView, this);
    crypto = new CryptoHandler(appView);
    mKey = new BrowserKey(appView, this);
    audio = new AudioHandler(appView, this);
    uiControls = new UIControls(appView, this);

    // This creates the new javascript interfaces for PhoneGap
    appView.addJavascriptInterface(gap, "DroidGap");
    appView.addJavascriptInterface(accel, "Accel");
    appView.addJavascriptInterface(launcher, "GapCam");
    appView.addJavascriptInterface(mContacts, "ContactHook");
    appView.addJavascriptInterface(fs, "FileUtil");
    appView.addJavascriptInterface(netMan, "NetworkManager");
    appView.addJavascriptInterface(mCompass, "CompassHook");
    appView.addJavascriptInterface(crypto, "GapCrypto");
    appView.addJavascriptInterface(mKey, "BackButton");
    appView.addJavascriptInterface(audio, "GapAudio");
    appView.addJavascriptInterface(uiControls, "UIControlsHook");

    if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
      cupcakeStorage = new Storage(appView);
      geo = new GeoBroker(appView, this);
      appView.addJavascriptInterface(cupcakeStorage, "droidStorage");
      appView.addJavascriptInterface(geo, "Geo");
    }
  }
예제 #2
0
/** @author Andreas Schildbach */
public final class Constants {
  public static final boolean TEST = R.class.getPackage().getName().contains("_test");

  /** Network this wallet is on (e.g. testnet or mainnet). */
  public static final NetworkParameters NETWORK_PARAMETERS =
      TEST ? TestNet3Params.get() : MainNetParams.get();

  public static final class Files {
    private static final String FILENAME_NETWORK_SUFFIX =
        NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? "" : "-testnet";

    /** Filename of the wallet. */
    public static final String WALLET_FILENAME_PROTOBUF =
        "wallet-protobuf" + FILENAME_NETWORK_SUFFIX;

    /** Filename of the automatic key backup (old format, can only be read). */
    public static final String WALLET_KEY_BACKUP_BASE58 =
        "key-backup-base58" + FILENAME_NETWORK_SUFFIX;

    /** Filename of the automatic wallet backup. */
    public static final String WALLET_KEY_BACKUP_PROTOBUF =
        "key-backup-protobuf" + FILENAME_NETWORK_SUFFIX;

    /** Path to external storage */
    public static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory();

    /** Manual backups go here. */
    public static final File EXTERNAL_WALLET_BACKUP_DIR =
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

    /** Filename of the manual key backup (old format, can only be read). */
    public static final String EXTERNAL_WALLET_KEY_BACKUP =
        "bitcoin-wallet-keys" + FILENAME_NETWORK_SUFFIX;

    /** Filename of the manual wallet backup. */
    public static final String EXTERNAL_WALLET_BACKUP =
        "bitcoin-wallet-backup" + FILENAME_NETWORK_SUFFIX;

    /** Filename of the block store for storing the chain. */
    public static final String BLOCKCHAIN_FILENAME = "blockchain" + FILENAME_NETWORK_SUFFIX;

    /** Filename of the block checkpoints file. */
    public static final String CHECKPOINTS_FILENAME =
        "checkpoints" + FILENAME_NETWORK_SUFFIX + ".txt";
  }

  /** Maximum size of backups. Files larger will be rejected. */
  public static final long BACKUP_MAX_CHARS = 10000000;

  private static final String BITEASY_API_URL_PROD = "https://api.biteasy.com/blockchain/v1/";
  private static final String BITEASY_API_URL_TEST = "https://api.biteasy.com/testnet/v1/";
  /** Base URL for blockchain API. */
  public static final String BITEASY_API_URL =
      NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET)
          ? BITEASY_API_URL_PROD
          : BITEASY_API_URL_TEST;

  /** URL to fetch version alerts from. */
  public static final String VERSION_URL = "https://wallet.schildbach.de/version";

  /** MIME type used for transmitting single transactions. */
  public static final String MIMETYPE_TRANSACTION = "application/x-btctx";

  /** MIME type used for transmitting wallet backups. */
  public static final String MIMETYPE_WALLET_BACKUP = "application/x-bitcoin-wallet-backup";

  /** Number of confirmations until a transaction is fully confirmed. */
  public static final int MAX_NUM_CONFIRMATIONS = 7;

  /** User-agent to use for network access. */
  public static final String USER_AGENT = "Bitcoin Wallet";

  /** Default currency to use if all default mechanisms fail. */
  public static final String DEFAULT_EXCHANGE_CURRENCY = "USD";

  /** Donation address for tip/donate action. */
  public static final String DONATION_ADDRESS = "18CK5k1gajRKKSC7yVSTXT9LUzbheh1XY4";

  /** Recipient e-mail address for reports. */
  public static final String REPORT_EMAIL = "*****@*****.**";

  /** Subject line for manually reported issues. */
  public static final String REPORT_SUBJECT_ISSUE = "Reported issue";

  /** Subject line for crash reports. */
  public static final String REPORT_SUBJECT_CRASH = "Crash report";

  public static final char CHAR_HAIR_SPACE = '\u200a';
  public static final char CHAR_THIN_SPACE = '\u2009';
  public static final char CHAR_ALMOST_EQUAL_TO = '\u2248';
  public static final char CHAR_CHECKMARK = '\u2713';
  public static final char CURRENCY_PLUS_SIGN = '\uff0b';
  public static final char CURRENCY_MINUS_SIGN = '\uff0d';
  public static final String PREFIX_ALMOST_EQUAL_TO =
      Character.toString(CHAR_ALMOST_EQUAL_TO) + CHAR_THIN_SPACE;
  public static final int ADDRESS_FORMAT_GROUP_SIZE = 4;
  public static final int ADDRESS_FORMAT_LINE_SIZE = 12;

  public static final MonetaryFormat LOCAL_FORMAT =
      new MonetaryFormat().noCode().minDecimals(2).optionalDecimals();

  public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();

  public static final String SOURCE_URL = "https://github.com/schildbach/bitcoin-wallet";
  public static final String BINARY_URL = "https://github.com/schildbach/bitcoin-wallet/releases";
  public static final String MARKET_APP_URL = "market://details?id=%s";
  public static final String WEBMARKET_APP_URL = "https://play.google.com/store/apps/details?id=%s";

  public static final int HTTP_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS;
  public static final int PEER_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS;

  public static final long LAST_USAGE_THRESHOLD_JUST_MS = DateUtils.HOUR_IN_MILLIS;
  public static final long LAST_USAGE_THRESHOLD_RECENTLY_MS = 2 * DateUtils.DAY_IN_MILLIS;

  public static final int SDK_JELLY_BEAN = 16;
  public static final int SDK_JELLY_BEAN_MR2 = 18;
  public static final int SDK_LOLLIPOP = 21;

  public static final int SDK_DEPRECATED_BELOW = Build.VERSION_CODES.ICE_CREAM_SANDWICH;

  public static final boolean BUG_OPENSSL_HEARTBLEED =
      Build.VERSION.SDK_INT == Constants.SDK_JELLY_BEAN
          && Build.VERSION.RELEASE.startsWith("4.1.1");

  public static final int MEMORY_CLASS_LOWEND = 48;
}
예제 #3
0
public class MainTabActivity extends TabActivity {
  private static final int DIALOG_LICENSEAGREEMENT = 0;

  private boolean tabsAdded;

  private static final String TAG_NORMAL = "normal";

  private static final String TAG_ALL = "all";

  private static final String TAG_FAVORITE = "favorite";

  public static MainTabActivity INSTANCE;

  public static final boolean POSTGINGERBREAD =
      !Build.VERSION.RELEASE.startsWith("1")
          && !Build.VERSION.RELEASE.startsWith("2"); // this way around is future save

  private static Boolean LIGHTTHEME;

  public static boolean isLightTheme(Context context) {
    if (LIGHTTHEME == null) {
      LIGHTTHEME =
          PreferenceManager.getDefaultSharedPreferences(context)
              .getBoolean(Strings.SETTINGS_LIGHTTHEME, false);
    }
    return LIGHTTHEME;
  }

  private Menu menu;

  private BroadcastReceiver refreshReceiver =
      new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
          internalSetProgressBarIndeterminateVisibility(true);
        }
      };

  private boolean hasContent;

  private boolean progressBarVisible;

  private Vector<String> visitedTabs;

  public void onCreate(Bundle savedInstanceState) {
    if (isLightTheme(this)) {
      setTheme(R.style.Theme_Light);
    }
    super.onCreate(savedInstanceState);

    // We need to display progress information
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

    setContentView(R.layout.tabs);
    INSTANCE = this;
    hasContent = false;
    visitedTabs = new Vector<String>(3);
    if (getPreferences(MODE_PRIVATE).getBoolean(Strings.PREFERENCE_LICENSEACCEPTED, false)) {
      setContent();
    } else {
      /* Workaround for android issue 4499 on 1.5 devices */
      getTabHost()
          .addTab(
              getTabHost()
                  .newTabSpec(Strings.EMPTY)
                  .setIndicator(Strings.EMPTY)
                  .setContent(new Intent(this, EmptyActivity.class)));

      showDialog(DIALOG_LICENSEAGREEMENT);
    }
  }

  @Override
  protected void onResume() {
    super.onResume();
    internalSetProgressBarIndeterminateVisibility(isCurrentlyRefreshing());
    registerReceiver(refreshReceiver, new IntentFilter("de.shandschuh.sparserss.REFRESH"));
  }

  @Override
  protected void onPause() {
    unregisterReceiver(refreshReceiver);
    super.onPause();
  }

  @Override
  protected Dialog onCreateDialog(int id) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.setIcon(android.R.drawable.ic_dialog_alert);
    builder.setTitle(R.string.dialog_licenseagreement);
    builder.setNegativeButton(
        R.string.button_decline,
        new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
            finish();
          }
        });
    builder.setPositiveButton(
        R.string.button_accept,
        new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();

            Editor editor = getPreferences(MODE_PRIVATE).edit();

            editor.putBoolean(Strings.PREFERENCE_LICENSEACCEPTED, true);
            editor.commit();

            /* Part of workaround for android issue 4499 on 1.5 devices */
            getTabHost().clearAllTabs();

            /* we only want to invoke actions if the license is accepted */
            setContent();
          }
        });
    setupLicenseText(builder);
    builder.setOnKeyListener(
        new OnKeyListener() {
          public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
              dialog.cancel();
              finish();
            }
            return true;
          }
        });
    return builder.create();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    this.menu = menu;

    Activity activity = getCurrentActivity();

    if (hasContent && activity != null) {
      return activity.onCreateOptionsMenu(menu);
    } else {
      menu.add(Strings.EMPTY); // to let the menu be available
      return true;
    }
  }

  @Override
  public boolean onMenuItemSelected(int featureId, MenuItem item) {
    Activity activity = getCurrentActivity();

    if (hasContent && activity != null) {
      return activity.onMenuItemSelected(featureId, item);
    } else {
      return super.onMenuItemSelected(featureId, item);
    }
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    Activity activity = getCurrentActivity();

    if (hasContent && activity != null) {
      return activity.onPrepareOptionsMenu(menu);
    } else {
      return super.onPrepareOptionsMenu(menu);
    }
  }

  private void setContent() {
    TabHost tabHost = getTabHost();

    tabHost.addTab(
        tabHost
            .newTabSpec(TAG_NORMAL)
            .setIndicator(getString(R.string.overview))
            .setContent(new Intent().setClass(this, RSSOverview.class)));
    hasContent = true;
    if (PreferenceManager.getDefaultSharedPreferences(this)
        .getBoolean(Strings.SETTINGS_SHOWTABS, false)) {
      setTabWidgetVisible(true);
    }
    final MainTabActivity mainTabActivity = this;
    if (POSTGINGERBREAD) {
      /* Change the menu also on ICS when tab is changed */
      tabHost.setOnTabChangedListener(
          new OnTabChangeListener() {
            public void onTabChanged(String tabId) {
              if (menu != null) {
                menu.clear();
                onCreateOptionsMenu(menu);
              }
              SharedPreferences.Editor editor =
                  PreferenceManager.getDefaultSharedPreferences(mainTabActivity).edit();
              editor.putString(Strings.PREFERENCE_LASTTAB, tabId);
              editor.commit();
              setCurrentTab(tabId);
            }
          });
      if (menu != null) {
        menu.clear();
        onCreateOptionsMenu(menu);
      }
    } else {
      tabHost.setOnTabChangedListener(
          new OnTabChangeListener() {
            @Override
            public void onTabChanged(String tabId) {
              setCurrentTab(tabId);
            }
          });
    }
  }

  private void setCurrentTab(String currentTab) {
    if (visitedTabs.contains(currentTab)) {
      // requery the tab but only if it has been shown already
      Activity activity = getCurrentActivity();

      if (hasContent && activity != null) {
        ((Requeryable) activity).requery();
      }
    } else {
      visitedTabs.add(currentTab);
    }
  }

  public void setTabWidgetVisible(boolean visible) {
    if (visible) {
      TabHost tabHost = getTabHost();
      if (!tabsAdded) {
        tabHost.addTab(
            tabHost
                .newTabSpec(TAG_ALL)
                .setIndicator(getString(R.string.all))
                .setContent(
                    new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.CONTENT_URI)
                        .putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true)));

        tabHost.addTab(
            tabHost
                .newTabSpec(TAG_FAVORITE)
                .setIndicator(
                    getString(R.string.favorites),
                    getResources().getDrawable(android.R.drawable.star_big_on))
                .setContent(
                    new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.FAVORITES_CONTENT_URI)
                        .putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true)
                        .putExtra(EntriesListActivity.EXTRA_AUTORELOAD, true)));
        tabsAdded = true;
      }
      getTabWidget().setVisibility(View.VISIBLE);

      String lastTab =
          PreferenceManager.getDefaultSharedPreferences(this)
              .getString(Strings.PREFERENCE_LASTTAB, TAG_NORMAL);
      boolean tabFound = false;
      for (int i = 0; i < tabHost.getTabWidget().getChildCount(); ++i) {
        tabHost.setCurrentTab(i);
        String currentTab = tabHost.getCurrentTabTag();
        if (lastTab.equals(currentTab)) {
          tabFound = true;
          break;
        }
      }
      if (!tabFound) {
        tabHost.setCurrentTab(0);
      }
    } else {
      getTabWidget().setVisibility(View.GONE);
    }
  }

  void setupLicenseText(AlertDialog.Builder builder) {
    View view = getLayoutInflater().inflate(R.layout.license, null);

    final TextView textView = (TextView) view.findViewById(R.id.license_text);

    textView.setTextColor(
        textView.getTextColors().getDefaultColor()); // disables color change on selection
    textView.setText(
        new StringBuilder(getString(R.string.license_intro))
            .append(Strings.THREENEWLINES)
            .append(getString(R.string.license)));

    final TextView contributorsTextView =
        (TextView) view.findViewById(R.id.contributors_togglebutton);

    contributorsTextView.setOnClickListener(
        new OnClickListener() {
          boolean showingLicense = true;

          @Override
          public void onClick(View view) {
            if (showingLicense) {
              textView.setText(R.string.contributors_list);
              contributorsTextView.setText(R.string.license_word);
            } else {
              textView.setText(
                  new StringBuilder(getString(R.string.license_intro))
                      .append(Strings.THREENEWLINES)
                      .append(getString(R.string.license)));
              contributorsTextView.setText(R.string.contributors);
            }
            showingLicense = !showingLicense;
          }
        });
    builder.setView(view);
  }

  private boolean isCurrentlyRefreshing() {
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
      if (FetcherService.class.getName().equals(service.service.getClassName())) {
        return true;
      }
    }
    return false;
  }

  public void internalSetProgressBarIndeterminateVisibility(boolean progressBarVisible) {
    setProgressBarIndeterminateVisibility(progressBarVisible);
    this.progressBarVisible = progressBarVisible;

    Activity activity = getCurrentActivity();

    if (activity != null) {
      activity.onPrepareOptionsMenu(null);
    }
  }

  public boolean isProgressBarVisible() {
    return progressBarVisible;
  }
}
예제 #4
0
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    getWindow()
        .setFlags(
            WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
    // This builds the view.  We could probably get away with NOT having a LinearLayout, but I like
    // having a bucket!

    LinearLayout.LayoutParams containerParams =
        new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0F);

    LinearLayout.LayoutParams webviewParams =
        new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 1.0F);

    root = new LinearLayout(this);
    root.setOrientation(LinearLayout.VERTICAL);
    root.setBackgroundColor(Color.BLACK);
    root.setLayoutParams(containerParams);

    appView = new WebView(this);
    appView.setLayoutParams(webviewParams);

    WebViewReflect.checkCompatibility();

    if (android.os.Build.VERSION.RELEASE.startsWith("2."))
      appView.setWebChromeClient(new EclairClient(this));
    else {
      appView.setWebChromeClient(new GapClient(this));
    }

    appView.setInitialScale(100);
    appView.setVerticalScrollBarEnabled(false);

    WebSettings settings = appView.getSettings();
    settings.setJavaScriptEnabled(true);
    settings.setJavaScriptCanOpenWindowsAutomatically(true);
    settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);

    Package pack = this.getClass().getPackage();
    String appPackage = pack.getName();

    WebViewReflect.setStorage(settings, true, "/data/data/" + appPackage + "/app_database/");

    // Disable cookies
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(false);

    // Turn on DOM storage!
    WebViewReflect.setDomStorage(settings);
    // Turn off native geolocation object in browser - we use our own :)
    WebViewReflect.setGeolocationEnabled(settings, true);
    /* Bind the appView object to the gap class methods */
    bindBrowser(appView);
    if (cupcakeStorage != null) cupcakeStorage.setStorage(appPackage);

    root.addView(appView);

    setContentView(root);
  }