Skip to content

Most visited

Recently visited

navigation
WatchFace / Application / src / com.example.android.wearable.watchface /

FitDistanceWatchFaceConfigActivity.java

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
}