Android Open Source - Speedometer Speedometer App






From Project

Back to project page Speedometer.

License

The source code is released under:

Apache License

If you think the Android project Speedometer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/* Copyright 2012 Google Inc.
 *//from   w w w. j  a v a 2 s .c  o  m
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.wireless.speed.speedometer;

import com.google.wireless.speed.speedometer.MeasurementScheduler.SchedulerBinder;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TabActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TabHost;
import android.widget.TextView;

import java.security.Security;

/**
 * The main UI thread that manages different tabs
 * @author wenjiezeng@google.com (Steve Zeng)
 *
 */
public class SpeedometerApp extends TabActivity {
  
  public static final String TAG = "Speedometer";
  
  private boolean userConsented = false;
  
  private static final int DIALOG_CONSENT = 0;
  private MeasurementScheduler scheduler;
  private TabHost tabHost;
  private boolean isBound = false;
  private boolean isBindingToService = false;
  private BroadcastReceiver receiver;
  TextView statusBar, statsBar;
  
  /** Defines callbacks for service binding, passed to bindService() */
  private ServiceConnection serviceConn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
      Logger.d("onServiceConnected called");
      // We've bound to LocalService, cast the IBinder and get LocalService
      // instance
      SchedulerBinder binder = (SchedulerBinder) service;
      scheduler = binder.getService();
      isBound = true;
      isBindingToService = false;
      initializeStatusBar();
      SpeedometerApp.this.sendBroadcast(new UpdateIntent("",
          UpdateIntent.SCHEDULER_CONNECTED_ACTION));
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
      Logger.d("onServiceDisconnected called");
      isBound = false;
    }
  };
  
  /** Returns the scheduler singleton instance. Should only be called from the UI thread. */
  public MeasurementScheduler getScheduler() {
    if (isBound) {
      return this.scheduler;
    } else {
      bindToService();
      return null;
    }
  }
  
  /** Returns the tab host. Allows child tabs to request focus changes, etc... */
  public TabHost getSpeedomterTabHost() {
    return tabHost;
  }
  
  private void setPauseIconBasedOnSchedulerState(MenuItem item) {
    if (this.scheduler != null && item != null) {
      if (this.scheduler.isPauseRequested()) {
        item.setIcon(android.R.drawable.ic_media_play);
        item.setTitle(R.string.menuResume);
      } else {
        item.setIcon(android.R.drawable.ic_media_pause);
        item.setTitle(R.string.menumPause);
      }
    }
  }
  
  /** Populate the application menu. Only called once per onCreate() */
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);
    return true;
  }
  
  /** Adjust menu items depending on system state. Called every time the
   *  menu pops up */
  @Override
  public boolean onPrepareOptionsMenu (Menu menu) {
    setPauseIconBasedOnSchedulerState(menu.findItem(R.id.menuPauseResume));
    return true;
  }
  
  /** React to menu item selections */
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
      case R.id.menuPauseResume:
        if (this.scheduler != null) {
          if (this.scheduler.isPauseRequested()) {
            this.scheduler.resume();
          } else {
            this.scheduler.pause();
          }
        }
        return true;
      case R.id.menuQuit:
        Logger.i("User requests exit. Quitting the app");
        quitApp();
        return true;
      case R.id.menuSettings:
        Intent settingsActivity = new Intent(getBaseContext(),
            SpeedometerPreferenceActivity.class);
        startActivity(settingsActivity);
        return true;
      case R.id.aboutPage:
        Intent intent = new Intent(getBaseContext(),
            AboutActivity.class);
        startActivity(intent);
        return true;
      case R.id.menuLog:
        intent = new Intent(getBaseContext(), SystemConsoleActivity.class);
        startActivity(intent);
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }
    
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    Logger.d("onCreate called");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    restoreConsentState();
    if (!userConsented) {
      /* Before doing anything, show the consent dialog. */
      showDialog(DIALOG_CONSENT);
    }
    
    /* Set the DNS cache TTL to 0 such that measurements can be more accurate.
     * However, it is known that the current Android OS does not take actions
     * on these properties but may enforce them in future versions.
     */ 
    System.setProperty("networkaddress.cache.ttl", "0");
    System.setProperty("networkaddress.cache.negative.ttl", "0");
    Security.setProperty("networkaddress.cache.ttl", "0");
    Security.setProperty("networkaddress.cache.negative.ttl", "0");

    Resources res = getResources(); // Resource object to get Drawables
    tabHost = getTabHost();  // The activity TabHost
    TabHost.TabSpec spec;  // Resusable TabSpec for each tab
    Intent intent;  // Reusable Intent for each tab

    // Do the same for the other tabs
    intent = new Intent().setClass(this, MeasurementCreationActivity.class);
    spec = tabHost.newTabSpec(MeasurementCreationActivity.TAB_TAG).setIndicator(
        "Measure", res.getDrawable(R.drawable.ic_tab_user_measurement)).setContent(intent);
    tabHost.addTab(spec);
    // Creates the user task console tab
    intent = new Intent().setClass(this, ResultsConsoleActivity.class);
    spec = tabHost.newTabSpec(ResultsConsoleActivity.TAB_TAG).setIndicator(
        "Results", res.getDrawable(R.drawable.ic_tab_results_icon)).setContent(intent);
    tabHost.addTab(spec);
    
    // Creates the measurement schedule console tab
    intent = new Intent().setClass(this, MeasurementScheduleConsoleActivity.class);
    spec = tabHost.newTabSpec(MeasurementScheduleConsoleActivity.TAB_TAG).setIndicator(
        "Task Queue", res.getDrawable(R.drawable.ic_tab_schedules)).setContent(intent);
    tabHost.addTab(spec);

    tabHost.setCurrentTabByTag(MeasurementCreationActivity.TAB_TAG);
    
    statusBar = (TextView) findViewById(R.id.systemStatusBar);
    statsBar = (TextView) findViewById(R.id.systemStatsBar);
    
    // We only need one instance of the scheduler thread
    intent = new Intent(this, MeasurementScheduler.class);
    this.startService(intent);
    
    this.receiver = new BroadcastReceiver() {
      @Override
      // All onXyz() callbacks are single threaded
      public void onReceive(Context context, Intent intent) {
        // Update the status bar on SYSTEM_STATUS_UPDATE_ACTION intents
        String statusMsg = intent.getStringExtra(UpdateIntent.STATUS_MSG_PAYLOAD);
        if (statusMsg != null) {
          updateStatusBar(statusMsg);
        } else if (scheduler != null) {
          initializeStatusBar();
        }
        
        String statsMsg = intent.getStringExtra(UpdateIntent.STATS_MSG_PAYLOAD);
        if (statsMsg != null) {
          updateStatsBar(statsMsg);
        }
      }
    };
    IntentFilter filter = new IntentFilter();
    filter.addAction(UpdateIntent.SYSTEM_STATUS_UPDATE_ACTION);
    this.registerReceiver(this.receiver, filter);
  }
  
  protected Dialog onCreateDialog(int id) {
    Logger.d("onCreateDialog called");
    switch(id) {
    case DIALOG_CONSENT:
      return showConsentDialog();
    default:
      return null;
    }
  }
  
  private void initializeStatusBar() {
    if (this.scheduler.isPauseRequested()) {
      updateStatusBar(SpeedometerApp.this.getString(R.string.pauseMessage));
    } else if (!scheduler.hasBatteryToScheduleExperiment()) {
      updateStatusBar(SpeedometerApp.this.getString(R.string.powerThreasholdReachedMsg));
    } else {
      MeasurementTask currentTask = scheduler.getCurrentTask();
      if (currentTask != null) {
        if (currentTask.getDescription().priority == MeasurementTask.USER_PRIORITY) {
          updateStatusBar("User task " + currentTask.getDescriptor() + " is running");
        } else {
          updateStatusBar("System task " + currentTask.getDescriptor() + " is running");
        }
      } else {
        updateStatusBar(SpeedometerApp.this.getString(R.string.resumeMessage));
      }
    }
  }
  
  private void updateStatusBar(String statusMsg) {
    if (statusMsg != null) {
      statusBar.setText(statusMsg);
    }
  }
  
  private void updateStatsBar(String statsMsg) {
    if (statsMsg != null) {
      statsBar.setText(statsMsg);
    }
  }
  
  private void bindToService() {
    if (!isBindingToService && !isBound) {
      // Bind to the scheduler service if it is not bounded
      Intent intent = new Intent(this, MeasurementScheduler.class);
      bindService(intent, serviceConn, Context.BIND_AUTO_CREATE);
      isBindingToService = true;
    }
  }
  
  private Dialog showConsentDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(getString(R.string.consentDialogMsg))
           .setCancelable(false)
           .setPositiveButton("Okay, got it", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int which) {
                recordUserConsent();
                // Enable auto start on boot.
                setStartOnBoot(true);
                // Force a checkin now since the one initiated by the scheduler was likely skipped.
                doCheckin();
              }
          })
           .setNegativeButton("No thanks", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                 quitApp();
               }
           });
    return builder.create(); 
  }
  
  
  @Override
  protected void onStart() {
    Logger.d("onStart called");
    // Bind to the scheduler service for only once during the lifetime of the activity
    bindToService();
    super.onStart();
  }
  
  @Override
  protected void onStop() {
    Logger.d("onStop called");
    super.onStop();
    if (isBound) {
      unbindService(serviceConn);
      isBound = false;
    }
  }
  
  @Override
  protected void onDestroy() {
    Logger.d("onDestroy called");
    super.onDestroy();
    this.unregisterReceiver(this.receiver);
  }

  private void quitApp() {
    Logger.d("quitApp called");
    if (isBound) {
      unbindService(serviceConn);
      isBound = false;
    }
    if (this.scheduler != null) {
      scheduler.requestStop();
    }
    // Force consent on next restart.
    userConsented = false;
    saveConsentState();
    // Disable auto start on boot.
    setStartOnBoot(false);
    
    this.finish();
    System.exit(0);
  }
  
  private void doCheckin() {
    if (scheduler != null) {
      scheduler.handleCheckin(true);
    }
  }
  
  /** Set preference to indicate whether start on boot is enabled. */
  private void setStartOnBoot(boolean startOnBoot) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
        getApplicationContext());
    SharedPreferences.Editor editor = prefs.edit();
    editor.putBoolean(getString(R.string.startOnBootPrefKey), startOnBoot);
    editor.commit();
  }
  
  private void recordUserConsent() {
    userConsented = true;
    saveConsentState();
  }
  
  /** Save consent state persistent storage. */
  private void saveConsentState() {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
        getApplicationContext());
    SharedPreferences.Editor editor = prefs.edit();
    editor.putBoolean(Config.PREF_KEY_CONSENTED, userConsented);
    editor.commit();
  }
  
  /**
   * Restore measurement statistics from persistent storage.
   */
  private void restoreConsentState() {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
        getApplicationContext());
    userConsented = prefs.getBoolean(Config.PREF_KEY_CONSENTED, false);
  }
}




Java Source Code List

com.google.wireless.speed.speedometer.AboutActivity.java
com.google.wireless.speed.speedometer.AccountSelector.java
com.google.wireless.speed.speedometer.BatteryCapPowerManager.java
com.google.wireless.speed.speedometer.Checkin.java
com.google.wireless.speed.speedometer.Config.java
com.google.wireless.speed.speedometer.DeviceInfo.java
com.google.wireless.speed.speedometer.DeviceProperty.java
com.google.wireless.speed.speedometer.Logger.java
com.google.wireless.speed.speedometer.MeasurementCreationActivity.java
com.google.wireless.speed.speedometer.MeasurementDesc.java
com.google.wireless.speed.speedometer.MeasurementError.java
com.google.wireless.speed.speedometer.MeasurementResult.java
com.google.wireless.speed.speedometer.MeasurementScheduleConsoleActivity.java
com.google.wireless.speed.speedometer.MeasurementScheduler.java
com.google.wireless.speed.speedometer.MeasurementSkippedException.java
com.google.wireless.speed.speedometer.MeasurementTask.java
com.google.wireless.speed.speedometer.ResultsConsoleActivity.java
com.google.wireless.speed.speedometer.SpeedometerApp.java
com.google.wireless.speed.speedometer.SpeedometerPreferenceActivity.java
com.google.wireless.speed.speedometer.SplashScreenActivity.java
com.google.wireless.speed.speedometer.SystemConsoleActivity.java
com.google.wireless.speed.speedometer.UpdateIntent.java
com.google.wireless.speed.speedometer.WatchdogBootReceiver.java
com.google.wireless.speed.speedometer.measurements.DnsLookupTask.java
com.google.wireless.speed.speedometer.measurements.HttpTask.java
com.google.wireless.speed.speedometer.measurements.PingTask.java
com.google.wireless.speed.speedometer.measurements.TracerouteTask.java
com.google.wireless.speed.speedometer.measurements.UDPBurstTask.java
com.google.wireless.speed.speedometer.util.MeasurementJsonConvertor.java
com.google.wireless.speed.speedometer.util.PhoneUtils.java
com.google.wireless.speed.speedometer.util.Util.java