Java tutorial
/* * * Copyright 2016 Michael A Updike * * 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.weebly.opus1269.clipman.msg; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.text.TextUtils; 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.api.GoogleApiClient; import com.google.api.client.extensions.android.json.AndroidJsonFactory; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.services.json.AbstractGoogleJsonClient; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.firebase.iid.FirebaseInstanceId; import com.weebly.opus1269.clipman.BuildConfig; import com.weebly.opus1269.clipman.R; import com.weebly.opus1269.clipman.app.Log; import com.weebly.opus1269.clipman.model.User; import java.io.IOException; import java.util.concurrent.TimeUnit; /** Base class for Google App Engine Endpoints */ abstract class Endpoint { /** Set to true to use local gae server */ final static private boolean USE_LOCAL_SERVER = false; /** Global Application Context */ final Context mContext; final String ERROR_UNKNOWN; final String ERROR_CREDENTIAL; final private String ERROR_ID_TOKEN; final private String ERROR_ACCOUNT; /** Log tag */ @SuppressWarnings("FieldCanBeLocal") final private String TAG = "Endpoint"; /** Access id */ final private String WEB_CLIENT_ID; /** Network timeout in millisecs */ final private int TIMEOUT = 40000; final private String ERROR_NOT_SIGNED_IN; /** Global NetHttpTransport instance */ private NetHttpTransport mNetHttpTransport = null; /** Global AndroidJacksonFactory instance */ private AndroidJsonFactory mAndroidJsonFactory = null; Endpoint(@NonNull Context context) { mContext = context.getApplicationContext(); ERROR_UNKNOWN = mContext.getString(R.string.err_unknown); ERROR_CREDENTIAL = mContext.getString(R.string.err_credential); ERROR_ACCOUNT = mContext.getString(R.string.err_account); ERROR_ID_TOKEN = mContext.getString(R.string.err_id_token); ERROR_NOT_SIGNED_IN = mContext.getString(R.string.err_not_signed_in); WEB_CLIENT_ID = mContext.getString(R.string.default_web_client_id); } /** * Determine if we are signed in * @return true if not signed in */ boolean notSignedIn() { if (!User.INST(mContext).isLoggedIn()) { Log.logD(TAG, ERROR_NOT_SIGNED_IN); return true; } return false; } /** * Get InstanceId (regToken) * @return regToken */ String getRegToken() throws IOException { String ret = FirebaseInstanceId.getInstance().getToken(); if (ret == null) { throw new IOException("Failed to get registration token."); } return ret; } /** * Get shared NetHttpTransport * @return regToken */ NetHttpTransport getNetHttpTransport() { if (mNetHttpTransport == null) { mNetHttpTransport = new NetHttpTransport(); } return mNetHttpTransport; } /** * Get shared AndroidJsonFactory * @return regToken */ AndroidJsonFactory getAndroidJsonFactory() { if (mAndroidJsonFactory == null) { mAndroidJsonFactory = new AndroidJsonFactory(); } return mAndroidJsonFactory; } /** * Get an idToken for authorization * @return idToken */ private String getIdToken() throws IOException { String idToken; // Get the IDToken that can be used securely on the backend for a short time final GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(WEB_CLIENT_ID).build(); // Build a GoogleApiClient with access to the Google Sign-In API and the // options specified by gso. final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(mContext) .addApi(Auth.GOOGLE_SIGN_IN_API, gso).build(); try { final ConnectionResult connRes = googleApiClient.blockingConnect(TIMEOUT, TimeUnit.MILLISECONDS); if (connRes.isSuccess()) { final GoogleSignInResult signInRes = Auth.GoogleSignInApi.silentSignIn(googleApiClient) .await(TIMEOUT, TimeUnit.MILLISECONDS); if (signInRes.isSuccess()) { final GoogleSignInAccount acct = signInRes.getSignInAccount(); if (acct != null) { idToken = acct.getIdToken(); } else { throw new IOException(ERROR_ACCOUNT); } } else { final String msg = signInRes.getStatus().toString(); throw new IOException(msg); } } else { final String msg = connRes.getErrorMessage() + "Code=" + connRes.getErrorCode(); throw new IOException(msg); } } catch (Exception ex) { final String msg = ERROR_ID_TOKEN + ": " + ex.getLocalizedMessage(); throw new IOException(msg); } finally { googleApiClient.disconnect(); } return idToken; } /** * Get a {@link GoogleCredential} for authorized server call * @param idToken - authorization token for user * @return {@link GoogleCredential} for authorized server call */ @Nullable GoogleCredential getCredential(String idToken) throws IOException { // get credential for a server call final GoogleCredential.Builder builder = new GoogleCredential.Builder(); final GoogleCredential credential = builder.setTransport(getNetHttpTransport()) .setJsonFactory(getAndroidJsonFactory()).build(); final String token; if (TextUtils.isEmpty(idToken)) { token = getIdToken(); } else { token = idToken; } if (TextUtils.isEmpty(token)) { return null; } credential.setAccessToken(token); return credential; } /** * Set setRootUrl and setGoogleClientRequestInitializer * for running with local server * @param builder JSON client */ void setLocalServer(AbstractGoogleJsonClient.Builder builder) { if (USE_LOCAL_SERVER && BuildConfig.DEBUG) { // options for running against local devappserver // - 10.0.2.2 is localhost's IP address in Android emulator // - turn off compression when running against local devappserver builder.setRootUrl("http://10.0.2.2:8080/_ah/api/") .setGoogleClientRequestInitializer(request -> request.setDisableGZipContent(true)); } } /** * Set timeout for authorized calls * @param requestInitializer initialize timeouts * @return HttpRequestInitializer */ HttpRequestInitializer setHttpTimeout(final HttpRequestInitializer requestInitializer) { return httpRequest -> { requestInitializer.initialize(httpRequest); httpRequest.setConnectTimeout(TIMEOUT); // connect timeout millisecs httpRequest.setReadTimeout(TIMEOUT); // read timeout millisecs }; } }