Android Open Source - Speedometer Account Selector






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.
 */*ww  w .j av  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 android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Helper class for google account checkins
 * 
 * @author mdw@google.com (Matt Welsh)
 * @author wenjiezeng@google.com (Steve Zeng)
 *
 */
public class AccountSelector {
  private static final String ACCOUNT_TYPE = "com.google";
  private static final String ACCOUNT_NAME = "@google.com";
  // The authentication period in milliseconds
  private static final long AUTHENTICATE_PERIOD_MSEC = 24 * 3600 * 1000;
  private Context context;
  private Checkin checkin;
  private String authToken = null;
  private ExecutorService checkinExecutor = null;
  private Future<Cookie> checkinFuture = null;
  private long lastAuthTime = 0;
  private boolean authImmediately = false;
  
  public AccountSelector(Context context, Checkin checkin) {
    this.context = context;
    this.checkin = checkin;
    this.checkinExecutor = Executors.newFixedThreadPool(1);
  }
  
  /** Returns the Future to monitor the checkin progress */
  public synchronized Future<Cookie> getCheckinFuture() {
    return this.checkinFuture;
  }
  
  /** After checkin finishes, the client of AccountSelector SHOULD reset checkinFuture */
  public synchronized void resetCheckinFuture() {
    this.checkinFuture = null;
  }
  
  /** Shuts down the executor thread */
  public void shutDown() {
    // shutdown() removes all previously submitted task and no new tasks are accepted 
    this.checkinExecutor.shutdown();
    // shutdownNow stops all currently executing tasks
    this.checkinExecutor.shutdownNow();
  }
  
  /** Allows clients of AccountSelector to request an authentication upon the next call
   * to authenticate() */
  public synchronized void setAuthImmediately(boolean val) {
    this.authImmediately = val;
  }
  
  private synchronized boolean shouldAuthImmediately() {
    return this.authImmediately;
  }
  
  private synchronized void setLastAuthTime(long lastTime) {
    this.lastAuthTime = lastTime;
  }
  
  private synchronized long getLastAuthTime() {
    return this.lastAuthTime;
  }
  
  /** Starts an authentication request  */
  public void authenticate() 
    throws OperationCanceledException, AuthenticatorException, IOException {
    Logger.i("AccountSelector.authenticate() running");
    /* We only need to authenticate every AUTHENTICATE_PERIOD_MILLI milliseconds, during
     * which we can reuse the cookie. If authentication fails due to expired
     * authToken, the client of AccountSelector can call authImmedately() to request
     * authenticate() upon the next checkin
     */
    long authTimeLast = this.getLastAuthTime();
    long timeSinceLastAuth = System.currentTimeMillis() - authTimeLast;
    if (!this.shouldAuthImmediately() && authTimeLast != 0 &&
        (timeSinceLastAuth < AUTHENTICATE_PERIOD_MSEC)) {
      return;
    }
    
    Logger.i("Authenticating. Last authentication is " + 
        timeSinceLastAuth / 1000 / 60 + " minutes ago. ");
    
    AccountManager accountManager = AccountManager.get(
        context.getApplicationContext());
    if (this.authToken != null) {
      // There will be no effect on the token if it is still valid
      Logger.i("Invalidating token");
      accountManager.invalidateAuthToken(ACCOUNT_TYPE, this.authToken);
    }
    
    Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
    Logger.i("Got " + accounts.length + " accounts");
    
    if (accounts != null && accounts.length > 0) {
      // TODO(mdw): If multiple accounts, need to pick the correct one
      Account accountToUse = accounts[0];
      // We prefer google's corporate account to personal accounts such as somebody@gmail.com
      for (Account account : accounts) {
        if (account.name.toLowerCase().trim().endsWith(ACCOUNT_NAME)) {
          Logger.i("Using the preferred google.com account: " + account.name);
          accountToUse = account;
          break;
        }
      }
      
      Logger.i("Trying to get auth token for " + accountToUse);
      
      AccountManagerFuture<Bundle> future = accountManager.getAuthToken(
          accountToUse, "ah", false, new AccountManagerCallback<Bundle>() {
        @Override
        public void run(AccountManagerFuture<Bundle> result) {
          Logger.i("AccountManagerCallback invoked");
          try {
            getAuthToken(result);
          } catch (RuntimeException e) {
            Logger.e("Failed to get authToken", e);
            /* TODO(Wenjie): May ask the user whether to quit the app nicely here if a number
             * of trials have been made and failed. Since Speedometer is basically useless 
             * without checkin
             */
          }
        }},
        null);
      Logger.i("AccountManager.getAuthToken returned " + future);
    } else {
      throw new RuntimeException("No google account found");
    }
  }
  
  private void getAuthToken(AccountManagerFuture<Bundle> result) {
    Logger.i("getAuthToken() called, result " + result);
    String errMsg = "Failed to get login cookie. ";
    Bundle bundle;
    try {
      bundle = result.getResult();
      Intent intent = (Intent) bundle.get(AccountManager.KEY_INTENT);
      if (intent != null) {
        // User input required. (A UI will pop up for user's consent to allow
        // this app access account information.)
        Logger.i("Starting account manager activity");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
      } else {
        Logger.i("Executing getCookie task");
        synchronized (this) {
          this.authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
          this.checkinFuture = checkinExecutor.submit(new GetCookieTask());
        }
      }
    } catch (OperationCanceledException e) {
      Logger.e(errMsg, e);
      throw new RuntimeException("Can't get login cookie", e);
    } catch (AuthenticatorException e) {
      Logger.e(errMsg, e);
      throw new RuntimeException("Can't get login cookie", e);
    } catch (IOException e) {
      Logger.e(errMsg, e);
      throw new RuntimeException("Can't get login cookie", e);
    }
  }
  
  private class GetCookieTask implements Callable<Cookie> {    
    @Override
    public Cookie call() {
      Logger.i("GetCookieTask running: " + authToken);
      DefaultHttpClient httpClient = new DefaultHttpClient();
      boolean success = false;
      try {
        String loginUrlPrefix = checkin.getServerUrl() +
          "/_ah/login?continue=" + checkin.getServerUrl() + 
          "&action=Login&auth=";
        // Don't follow redirects
        httpClient.getParams().setBooleanParameter(
            ClientPNames.HANDLE_REDIRECTS, false);
        HttpGet httpGet = new HttpGet(loginUrlPrefix + authToken);
        HttpResponse response;
        Logger.i("Accessing: " + loginUrlPrefix + authToken);
        response = httpClient.execute(httpGet);
        if (response.getStatusLine().getStatusCode() != 302) {
          // Response should be a redirect to the "continue" URL.
          Logger.e("Failed to get login cookie: " +
              loginUrlPrefix + " returned unexpected error code " +
              response.getStatusLine().getStatusCode());
          throw new RuntimeException("Failed to get login cookie: " +
              loginUrlPrefix + " returned unexpected error code " +
              response.getStatusLine().getStatusCode());
        }
        
        Logger.i("Got " + 
            httpClient.getCookieStore().getCookies().size() + " cookies back");
        
        for (Cookie cookie : httpClient.getCookieStore().getCookies()) {
          Logger.i("Checking cookie " + cookie);
          if (cookie.getName().equals("SACSID")
              || cookie.getName().equals("ACSID")) {
            Logger.i("Got cookie " + cookie);
            setLastAuthTime(System.currentTimeMillis());
            success = true;
            return cookie;
          }
        }
        Logger.e("No (S)ASCID cookies returned");
        throw new RuntimeException("Failed to get login cookie: " +
            loginUrlPrefix + " did not return any (S)ACSID cookie");
      } catch (ClientProtocolException e) {
        Logger.e("Failed to get login cookie", e);
        throw new RuntimeException("Failed to get login cookie", e);
      } catch (IOException e) {
        Logger.e("Failed to get login cookie", e);
        throw new RuntimeException("Failed to get login cookie", e);
      } finally {
        httpClient.getParams().setBooleanParameter(
            ClientPNames.HANDLE_REDIRECTS, true);
        if (!success) {
          resetCheckinFuture();
        }
      }
    }
  }
    

}




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