Home | History | Annotate | Download | only in com.example.android.wearable.watchface
      1 package com.example.android.wearable.watchface;
      2 
      3 import com.google.android.gms.common.ConnectionResult;
      4 import com.google.android.gms.common.GooglePlayServicesUtil;
      5 import com.google.android.gms.common.Scopes;
      6 import com.google.android.gms.common.api.GoogleApiClient;
      7 import com.google.android.gms.common.api.PendingResult;
      8 import com.google.android.gms.common.api.ResultCallback;
      9 import com.google.android.gms.common.api.Scope;
     10 import com.google.android.gms.common.api.Status;
     11 import com.google.android.gms.fitness.Fitness;
     12 
     13 import android.app.Activity;
     14 import android.content.Context;
     15 import android.content.Intent;
     16 import android.content.IntentSender;
     17 import android.content.SharedPreferences;
     18 import android.os.Bundle;
     19 import android.util.Log;
     20 import android.view.View;
     21 import android.widget.Switch;
     22 import android.widget.Toast;
     23 
     24 import java.util.concurrent.TimeUnit;
     25 
     26 /**
     27  * Allows users of the Fit WatchFace to tie their Google Fit account to the WatchFace.
     28  */
     29 public class FitDistanceWatchFaceConfigActivity extends Activity implements
     30         GoogleApiClient.ConnectionCallbacks,
     31         GoogleApiClient.OnConnectionFailedListener {
     32 
     33     private static final String TAG = "FitDistanceConfig";
     34 
     35     // Request code for launching the Intent to resolve authorization.
     36     private static final int REQUEST_OAUTH = 1;
     37 
     38     // Shared Preference used to record if the user has enabled Google Fit previously.
     39     private static final String PREFS_FIT_ENABLED_BY_USER =
     40             "com.example.android.wearable.watchface.preferences.FIT_ENABLED_BY_USER";
     41 
     42     /* Tracks whether an authorization activity is stacking over the current activity, i.e., when
     43      *  a known auth error is being resolved, such as showing the account chooser or presenting a
     44      *  consent dialog. This avoids common duplications as might happen on screen rotations, etc.
     45      */
     46     private static final String EXTRA_AUTH_STATE_PENDING =
     47             "com.example.android.wearable.watchface.extra.AUTH_STATE_PENDING";
     48 
     49     private static final long FIT_DISABLE_TIMEOUT_SECS = TimeUnit.SECONDS.toMillis(5);;
     50 
     51     private boolean mResolvingAuthorization;
     52 
     53     private boolean mFitEnabled;
     54 
     55     private GoogleApiClient mGoogleApiClient;
     56 
     57     private Switch mFitAuthSwitch;
     58 
     59     @Override
     60     protected void onCreate(Bundle savedInstanceState) {
     61         super.onCreate(savedInstanceState);
     62         setContentView(R.layout.activity_fit_watch_face_config);
     63 
     64         mFitAuthSwitch = (Switch) findViewById(R.id.fit_auth_switch);
     65 
     66         if (savedInstanceState != null) {
     67             mResolvingAuthorization =
     68                     savedInstanceState.getBoolean(EXTRA_AUTH_STATE_PENDING, false);
     69         } else {
     70             mResolvingAuthorization = false;
     71         }
     72 
     73         // Checks if user previously enabled/approved Google Fit.
     74         SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
     75         mFitEnabled =
     76                 sharedPreferences.getBoolean(PREFS_FIT_ENABLED_BY_USER, false);
     77 
     78         mGoogleApiClient = new GoogleApiClient.Builder(this)
     79                 .addApi(Fitness.HISTORY_API)
     80                 .addApi(Fitness.RECORDING_API)
     81                 .addApi(Fitness.CONFIG_API)
     82                 .addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
     83                 .addConnectionCallbacks(this)
     84                 .addOnConnectionFailedListener(this)
     85                 .build();
     86     }
     87 
     88     @Override
     89     protected void onStart() {
     90         super.onStart();
     91 
     92         if ((mFitEnabled) && (mGoogleApiClient != null)) {
     93 
     94             mFitAuthSwitch.setChecked(true);
     95             mFitAuthSwitch.setEnabled(true);
     96 
     97             mGoogleApiClient.connect();
     98 
     99         } else {
    100 
    101             mFitAuthSwitch.setChecked(false);
    102             mFitAuthSwitch.setEnabled(true);
    103         }
    104     }
    105 
    106     @Override
    107     protected void onStop() {
    108         super.onStop();
    109 
    110         if ((mGoogleApiClient != null) && (mGoogleApiClient.isConnected())) {
    111             mGoogleApiClient.disconnect();
    112         }
    113     }
    114 
    115     @Override
    116     protected void onSaveInstanceState(Bundle bundle) {
    117         super.onSaveInstanceState(bundle);
    118         bundle.putBoolean(EXTRA_AUTH_STATE_PENDING, mResolvingAuthorization);
    119     }
    120 
    121     @Override
    122     protected void onRestoreInstanceState(Bundle savedInstanceState) {
    123         super.onRestoreInstanceState(savedInstanceState);
    124 
    125         if (savedInstanceState != null) {
    126             mResolvingAuthorization =
    127                     savedInstanceState.getBoolean(EXTRA_AUTH_STATE_PENDING, false);
    128         }
    129     }
    130 
    131     @Override
    132     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    133         Log.d(TAG, "onActivityResult()");
    134 
    135         if (requestCode == REQUEST_OAUTH) {
    136             mResolvingAuthorization = false;
    137 
    138             if (resultCode == RESULT_OK) {
    139                 setUserFitPreferences(true);
    140 
    141                 if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) {
    142                     mGoogleApiClient.connect();
    143                 }
    144             } else {
    145                 // User cancelled authorization, reset the switch.
    146                 setUserFitPreferences(false);
    147             }
    148         }
    149     }
    150 
    151     @Override
    152     public void onConnected(Bundle connectionHint) {
    153         Log.d(TAG, "onConnected: " + connectionHint);
    154     }
    155 
    156     @Override
    157     public void onConnectionSuspended(int cause) {
    158 
    159         if (cause == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
    160             Log.i(TAG, "Connection lost.  Cause: Network Lost.");
    161         } else if (cause == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
    162             Log.i(TAG, "Connection lost.  Reason: Service Disconnected");
    163         } else {
    164             Log.i(TAG, "onConnectionSuspended: " + cause);
    165         }
    166 
    167         mFitAuthSwitch.setChecked(false);
    168         mFitAuthSwitch.setEnabled(true);
    169     }
    170 
    171     @Override
    172     public void onConnectionFailed(ConnectionResult result) {
    173         Log.d(TAG, "Connection to Google Fit failed. Cause: " + result.toString());
    174 
    175         if (!result.hasResolution()) {
    176             // User cancelled authorization, reset the switch.
    177             mFitAuthSwitch.setChecked(false);
    178             mFitAuthSwitch.setEnabled(true);
    179             // Show the localized error dialog
    180             GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show();
    181             return;
    182         }
    183 
    184         // Resolve failure if not already trying/authorizing.
    185         if (!mResolvingAuthorization) {
    186             try {
    187                 Log.i(TAG, "Attempting to resolve failed GoogleApiClient connection");
    188                 mResolvingAuthorization = true;
    189                 result.startResolutionForResult(this, REQUEST_OAUTH);
    190             } catch (IntentSender.SendIntentException e) {
    191                 Log.e(TAG, "Exception while starting resolution activity", e);
    192             }
    193         }
    194     }
    195 
    196     public void onSwitchClicked(View view) {
    197 
    198         boolean userWantsToEnableFit = mFitAuthSwitch.isChecked();
    199 
    200         if (userWantsToEnableFit) {
    201 
    202             Log.d(TAG, "User wants to enable Fit.");
    203             if ((mGoogleApiClient != null) && (!mGoogleApiClient.isConnected())) {
    204                 mGoogleApiClient.connect();
    205             }
    206 
    207         } else {
    208             Log.d(TAG, "User wants to disable Fit.");
    209 
    210             // Disable switch until disconnect request is finished.
    211             mFitAuthSwitch.setEnabled(false);
    212 
    213             PendingResult<Status> pendingResult = Fitness.ConfigApi.disableFit(mGoogleApiClient);
    214 
    215             pendingResult.setResultCallback(new ResultCallback<Status>() {
    216                 @Override
    217                 public void onResult(Status status) {
    218 
    219                     if (status.isSuccess()) {
    220                         Toast.makeText(
    221                                 FitDistanceWatchFaceConfigActivity.this,
    222                                 "Disconnected from Google Fit.",
    223                                 Toast.LENGTH_LONG).show();
    224 
    225                         setUserFitPreferences(false);
    226 
    227                         mGoogleApiClient.disconnect();
    228 
    229 
    230                     } else {
    231                         Toast.makeText(
    232                                 FitDistanceWatchFaceConfigActivity.this,
    233                                 "Unable to disconnect from Google Fit. See logcat for details.",
    234                                 Toast.LENGTH_LONG).show();
    235 
    236                         // Re-set the switch since auth failed.
    237                         setUserFitPreferences(true);
    238                     }
    239                 }
    240             }, FIT_DISABLE_TIMEOUT_SECS, TimeUnit.SECONDS);
    241         }
    242     }
    243 
    244     private void setUserFitPreferences(boolean userFitPreferences) {
    245 
    246         mFitEnabled = userFitPreferences;
    247         SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
    248         SharedPreferences.Editor editor = sharedPreferences.edit();
    249         editor.putBoolean(PREFS_FIT_ENABLED_BY_USER, userFitPreferences);
    250         editor.commit();
    251 
    252         mFitAuthSwitch.setChecked(userFitPreferences);
    253         mFitAuthSwitch.setEnabled(true);
    254     }
    255 }
    256