package com.github.akinaru.hcidebugger.activity; import android.accounts.Account; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.github.akinaru.hcidebugger.R; import com.google.android.gms.auth.api.Auth; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.auth.api.signin.GoogleSignInResult; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.SignInButton; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.OptionalPendingResult; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Scope; import com.google.android.gms.common.api.Status; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.youtube.YouTube; import com.google.api.services.youtube.model.Subscription; import com.google.api.services.youtube.model.SubscriptionListResponse; import java.io.IOException; import java.util.Collections; import java.util.List; /** * Activity to demonstrate using the Google Sign In API with a Google API that uses the Google * Java Client Library rather than a Google Play services API. See {@link GetContactsTask} * for how to access the People API using this method. *

* In order to use this Activity you must enable the People API on your project. Visit the following * link and replace 'YOUR_PROJECT_ID' to enable the API: * https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=YOUR_PROJECT_ID */ public class RestApiActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener { private static final String TAG = "RestApiActivity"; // Scope for reading user's contacts private static final String YOUTUBE_SCOPE = "https://www.googleapis.com/auth/youtube"; // Bundle key for account object private static final String KEY_ACCOUNT = "key_account"; // Request codes private static final int RC_SIGN_IN = 9001; private static final int RC_RECOVERABLE = 9002; // Global instance of the HTTP transport private static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport(); // Global instance of the JSON factory private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); private GoogleApiClient mGoogleApiClient; private Account mAccount; private TextView mStatusTextView; private TextView mDetailTextView; private ProgressDialog mProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Views mStatusTextView = (TextView) findViewById(R.id.status); mDetailTextView = (TextView) findViewById(R.id.detail); // Button listeners findViewById(R.id.sign_in_button).setOnClickListener(this); findViewById(R.id.sign_out_button).setOnClickListener(this); // For this example we don't need the disconnect button findViewById(R.id.disconnect_button).setVisibility(View.GONE); // Restore instance state if (savedInstanceState != null) { mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT); } // Configure sign-in to request the user's ID, email address, basic profile, // and readonly access to contacts. GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(new Scope(YOUTUBE_SCOPE)) .requestEmail() .build(); // Build a GoogleApiClient with access to the Google Sign-In API and the // options specified by gso. mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Auth.GOOGLE_SIGN_IN_API, gso) .build(); // Show a standard Google Sign In button. If your application does not rely on Google Sign // In for authentication you could replace this with a "Get Google Contacts" button // or similar. SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button); signInButton.setSize(SignInButton.SIZE_STANDARD); } @Override public void onStart() { super.onStart(); OptionalPendingResult opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient); if (opr.isDone()) { // If the user's cached credentials are valid, the OptionalPendingResult will be "done" // and the GoogleSignInResult will be available instantly. Log.d(TAG, "Got cached sign-in"); GoogleSignInResult result = opr.get(); handleSignInResult(result); } else { // If the user has not previously signed in on this device or the sign-in has expired, // this asynchronous branch will attempt to sign in the user silently. Cross-device // single sign-on will occur in this branch. showProgressDialog(); opr.setResultCallback(new ResultCallback() { @Override public void onResult(GoogleSignInResult googleSignInResult) { hideProgressDialog(); handleSignInResult(googleSignInResult); } }); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_ACCOUNT, mAccount); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); if (requestCode == RC_SIGN_IN) { GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); handleSignInResult(result); } // Handling a user-recoverable auth exception if (requestCode == RC_RECOVERABLE) { if (resultCode == RESULT_OK) { getSubscriptions(); } else { Toast.makeText(this, "failed", Toast.LENGTH_SHORT).show(); } } } private void signIn() { Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); startActivityForResult(signInIntent, RC_SIGN_IN); } private void signOut() { // Signing out clears the current authentication state and resets the default user, // this should be used to "switch users" without fully un-linking the user's google // account from your application. Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( new ResultCallback() { @Override public void onResult(@NonNull Status status) { updateUI(false); } }); } private void handleSignInResult(GoogleSignInResult result) { Log.d(TAG, "handleSignInResult:" + result.isSuccess()); if (result.isSuccess()) { // Get the account from the sign in result GoogleSignInAccount account = result.getSignInAccount(); // Signed in successfully, show authenticated UI. mStatusTextView.setText(account.getDisplayName()); updateUI(true); // Store the account from the result mAccount = account.getAccount(); // Asynchronously access the People API for the account getSubscriptions(); } else { Log.v(TAG, "fail : " + result.getStatus()); // Clear the local account mAccount = null; // Signed out, show unauthenticated UI. updateUI(false); } } private void getSubscriptions() { if (mAccount == null) { Log.w(TAG, "getContacts: null account"); return; } new GetSubscriptionTask().execute(mAccount); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.w(TAG, "onConnectionFailed:" + connectionResult); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.sign_in_button: signIn(); break; case R.id.sign_out_button: signOut(); break; } } private void showProgressDialog() { if (mProgressDialog == null) { mProgressDialog = new ProgressDialog(this); mProgressDialog.setMessage("loading"); mProgressDialog.setIndeterminate(true); } mProgressDialog.show(); } private void hideProgressDialog() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.hide(); } } private void updateUI(boolean signedIn) { if (signedIn) { findViewById(R.id.sign_in_button).setVisibility(View.GONE); findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE); } else { mStatusTextView.setText("signout"); mDetailTextView.setText(null); findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE); findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE); } } /** * AsyncTask that uses the credentials from Google Sign In to access Youtube subscription API. */ private class GetSubscriptionTask extends AsyncTask> { @Override protected void onPreExecute() { showProgressDialog(); } @Override protected List doInBackground(Account... params) { try { GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2( RestApiActivity.this, Collections.singleton(YOUTUBE_SCOPE)); credential.setSelectedAccount(params[0]); YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) .setApplicationName("Google Sign In Quickstart") .build(); SubscriptionListResponse connectionsResponse = youtube .subscriptions() .list("snippet") .setChannelId("UCfyuWgCPu5WneQwuLBWd7Pg") .execute(); return connectionsResponse.getItems(); } catch (UserRecoverableAuthIOException userRecoverableException) { Log.w(TAG, "getSubscription:recoverable exception", userRecoverableException); startActivityForResult(userRecoverableException.getIntent(), RC_RECOVERABLE); } catch (IOException e) { Log.w(TAG, "getSubscription:exception", e); } return null; } @Override protected void onPostExecute(List subscriptions) { hideProgressDialog(); if (subscriptions != null) { Log.d(TAG, "subscriptions : size=" + subscriptions.size()); // Get names of all connections StringBuilder msg = new StringBuilder(); for (int i = 0; i < subscriptions.size(); i++) { Log.v(TAG, "subscription : " + subscriptions.get(i).getId()); } // Display names mDetailTextView.setText(msg.toString()); } else { Log.d(TAG, "subscriptions: null"); mDetailTextView.setText("None"); } } } }