Skip to content

Instantly share code, notes, and snippets.

@bertrandmartel
Last active September 4, 2022 18:37
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bertrandmartel/7d323b09af889f5c03b862612c796046 to your computer and use it in GitHub Desktop.
Save bertrandmartel/7d323b09af889f5c03b862612c796046 to your computer and use it in GitHub Desktop.
Example of using Google Signin to access Youtube subscription API
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="4"
tools:context=".SignInActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/google_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="10dp"/>
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="title"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="36sp" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="signout"
android:textColor="@android:color/white"
android:textSize="14sp" />
<TextView
android:id="@+id/detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fadeScrollbars="true"
android:gravity="center"
android:maxLines="5"
android:padding="10dp"
android:scrollbars="vertical"
android:textColor="@android:color/white"
android:textSize="14sp" />
<Button
android:id="@+id/button_optional_action"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:text="Optional Action"
tools:visibility="visible" />
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible"
tools:visibility="gone" />
<LinearLayout
android:id="@+id/sign_out_and_disconnect"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:visibility="gone"
tools:visibility="visible">
<Button
android:id="@+id/sign_out_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="signout"/>
<Button
android:id="@+id/disconnect_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="disconnect" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.example.test"
minSdkVersion 19
targetSdkVersion 24
versionCode 12
versionName "1.83"
}
buildTypes {
release {
minifyEnabled true
zipAlignEnabled true
signingConfig signingConfigs.playStore
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:24.2.0"
compile 'com.android.support:design:24.2.0'
compile 'com.android.support:recyclerview-v7:24.2.0'
compile 'com.google.android.gms:play-services-auth:10.0.1'
compile 'com.google.api-client:google-api-client-android:1.22.0' exclude module: 'httpclient'
compile 'com.google.apis:google-api-services-youtube:v3-rev182-1.22.0'
}
apply plugin: 'com.google.gms.google-services'
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.
* <p>
* 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<GoogleSignInResult> 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<GoogleSignInResult>() {
@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<Status>() {
@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<Account, Void, List<Subscription>> {
@Override
protected void onPreExecute() {
showProgressDialog();
}
@Override
protected List<Subscription> 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<Subscription> 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");
}
}
}
}
@mathiarasan24
Copy link

Hi,

GoogleAccountCredential.usingOAuth2 this method used to log in right, why are you using this method to get subscription SubscriptionListResponse. It looks like another time login.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment