Advertisement
Guest User

Untitled

a guest
Jan 19th, 2017
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.83 KB | None | 0 0
  1. // Google Sign In
  2. compile 'com.google.android.gms:play-services-auth:10.0.1'
  3.  
  4. // Drive REST API
  5. compile('com.google.apis:google-api-services-drive:v3-rev54-1.22.0') {
  6. exclude group: 'org.apache.httpcomponents'
  7. }
  8.  
  9. @Override
  10. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  11. super.onActivityResult(requestCode, resultCode, data);
  12.  
  13. // Callback from Signin (Auth.GoogleSignInApi.getSignInIntent)
  14. if (requestCode == 1) {
  15. GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
  16. _googleApi.handleSignInResult(result);
  17. }
  18. }
  19.  
  20. import android.app.Activity;
  21. import android.content.Context;
  22. import android.content.Intent;
  23. import android.content.SharedPreferences;
  24. import android.content.pm.ApplicationInfo;
  25. import android.os.Bundle;
  26. import android.os.Handler;
  27. import android.util.Log;
  28.  
  29. import com.google.android.gms.auth.api.Auth;
  30. import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
  31. import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
  32. import com.google.android.gms.auth.api.signin.GoogleSignInResult;
  33. import com.google.android.gms.common.ConnectionResult;
  34. import com.google.android.gms.common.api.GoogleApiClient;
  35. import com.google.android.gms.common.api.ResultCallback;
  36. import com.google.android.gms.common.api.Scope;
  37. import com.google.android.gms.common.api.Status;
  38. import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
  39. import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
  40. import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
  41. import com.google.api.client.http.HttpTransport;
  42. import com.google.api.client.http.javanet.NetHttpTransport;
  43. import com.google.api.client.json.JsonFactory;
  44. import com.google.api.client.json.jackson2.JacksonFactory;
  45. import com.google.api.services.drive.Drive;
  46. import com.google.api.services.drive.model.File;
  47. import com.google.api.services.drive.model.FileList;
  48.  
  49. import java.io.IOException;
  50. import java.util.ArrayList;
  51. import java.util.List;
  52. import java.util.Locale;
  53.  
  54.  
  55. public class GoogleApi implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
  56.  
  57. private Context _context;
  58. private Handler _handler;
  59. private GoogleCredential _credential;
  60. private Drive _drive;
  61.  
  62. private GoogleApiClient _googleApiClient; // only set during login process
  63. private Activity _activity; // launch intent for login (UI)
  64.  
  65. // Saved to data store
  66. private boolean _loggedIn;
  67. private String _refreshToken; // store, even if user is logged out as we may need to reuse
  68.  
  69.  
  70. private static final String ClientID = "xxxxxx.apps.googleusercontent.com"; // web client
  71. private static final String ClientSecret = "xxxxx"; // web client
  72.  
  73. private class FileAndErrorMsg {
  74. public File file;
  75. public String errorMsg;
  76. public FileAndErrorMsg (File file_, String errorMsg_) { file = file_; errorMsg = errorMsg_; }
  77. }
  78. private class FileListAndErrorMsg {
  79. public List<File> fileList;
  80. public String errorMsg;
  81. public FileListAndErrorMsg (List<File> fileList_, String errorMsg_) { fileList = fileList_; errorMsg = errorMsg_; }
  82. }
  83.  
  84. // -------------------
  85. // Constructor
  86. // -------------------
  87.  
  88.  
  89. public GoogleApi (Context context) {
  90.  
  91. _context = context;
  92. _handler = new Handler();
  93. loadFromPrefs(); // loggedIn, refreshToken
  94.  
  95. // create credential; will refresh itself automatically (in Drive calls) as long as valid refresh token exists
  96. HttpTransport transport = new NetHttpTransport();
  97. JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
  98. _credential = new GoogleCredential.Builder()
  99. .setTransport(transport)
  100. .setJsonFactory(jsonFactory)
  101. .setClientSecrets(ClientID, ClientSecret) // .addRefreshListener
  102. .build();
  103. _credential.setRefreshToken(_refreshToken);
  104.  
  105. // Get app name from Manifest (for Drive builder)
  106. ApplicationInfo appInfo = context.getApplicationInfo();
  107. String appName = appInfo.labelRes == 0 ? appInfo.nonLocalizedLabel.toString() : context.getString(appInfo.labelRes);
  108.  
  109. _drive = new Drive.Builder(transport, jsonFactory, _credential).setApplicationName(appName).build();
  110. }
  111.  
  112. // -------------------
  113. // Auth
  114. // -------------------
  115.  
  116. // https://developers.google.com/identity/sign-in/android/offline-access#before_you_begin
  117. // https://developers.google.com/identity/sign-in/android/offline-access#enable_server-side_api_access_for_your_app
  118. // https://android-developers.googleblog.com/2016/02/using-credentials-between-your-server.html
  119. // https://android-developers.googleblog.com/2016/05/improving-security-and-user-experience.html
  120.  
  121.  
  122. public boolean isLoggedIn () {
  123. return _loggedIn;
  124. }
  125.  
  126. public void startAuth(Activity activity) {
  127. startAuth(activity, false);
  128. }
  129.  
  130. public void startAuth(Activity activity, boolean forceRefreshToken) {
  131.  
  132. _activity = activity;
  133. _loggedIn = false;
  134. saveToPrefs();
  135.  
  136. GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
  137. .requestScopes(new Scope("https://www.googleapis.com/auth/drive"))
  138. .requestServerAuthCode(ClientID, forceRefreshToken) // if force, guaranteed to get back refresh token, but will show "offline access?" if Google already issued refresh token
  139. .build();
  140.  
  141. _googleApiClient = new GoogleApiClient.Builder(activity)
  142. .addConnectionCallbacks(this)
  143. .addOnConnectionFailedListener(this)
  144. .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
  145. .build();
  146.  
  147. _googleApiClient.connect();
  148. }
  149.  
  150. @Override
  151. public void onConnected(Bundle connectionHint) {
  152. // Called soon after .connect()
  153. // This is only called when starting our Login process. Sign Out first so select-account screen shown. (OK if not already signed in)
  154. Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
  155. @Override
  156. public void onResult(Status status) {
  157. // Start sign in
  158. Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(_googleApiClient);
  159. _activity.startActivityForResult(signInIntent, 1); // Activity's onActivityResult will use the same code: 1
  160. }
  161. });
  162. }
  163.  
  164. @Override
  165. public void onConnectionSuspended(int cause) {
  166. authDone("Connection suspended.");
  167. }
  168. @Override
  169. public void onConnectionFailed(ConnectionResult connectionResult) { authDone("Connection failed."); }
  170.  
  171. public void handleSignInResult(GoogleSignInResult result) {
  172.  
  173. // Callback from Activity > onActivityResult
  174. if (result.isSuccess()) {
  175. GoogleSignInAccount acct = result.getSignInAccount();
  176. String authCode = acct.getServerAuthCode();
  177. new Thread(new ContinueAuthWithAuthCode_Background(authCode)).start();
  178. }
  179. else authDone("Login canceled or unable to connect to Google."); // can we get better error message?
  180. }
  181.  
  182. private class ContinueAuthWithAuthCode_Background implements Runnable {
  183.  
  184. String _authCode;
  185. public ContinueAuthWithAuthCode_Background (String authCode) {
  186. _authCode = authCode;
  187. }
  188. public void run() {
  189.  
  190. // Convert authCode to tokens
  191. GoogleTokenResponse tokenResponse = null;
  192. String errorMsg = null;
  193. try {
  194. tokenResponse = new GoogleAuthorizationCodeTokenRequest(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), "https://www.googleapis.com/oauth2/v4/token", ClientID, ClientSecret, _authCode, "").execute();
  195. }
  196. catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
  197. final GoogleTokenResponse tokenResponseFinal = tokenResponse;
  198. final String errorMsgFinal = errorMsg;
  199.  
  200. _handler.post(new Runnable() { public void run() {
  201. // Main thread
  202. GoogleTokenResponse tokenResponse = tokenResponseFinal;
  203. String errorMsg = errorMsgFinal;
  204. if (tokenResponse != null && errorMsg == null) {
  205. _credential.setFromTokenResponse(tokenResponse); // this will keep old refresh token if no new one sent
  206. _refreshToken = _credential.getRefreshToken();
  207. _loggedIn = true;
  208. saveToPrefs();
  209. // FIXME: if our refresh token is bad and we're not getting a new one, how do we deal with this?
  210. Log("New refresh token: " + tokenResponse.getRefreshToken());
  211. }
  212. else if (errorMsg == null) errorMsg = "Get token error."; // shouldn't get here
  213. authDone(errorMsg);
  214. } });
  215. }
  216. }
  217.  
  218. private void authDone(String errorMsg) {
  219. // Disconnect (we only need googleApiClient for login process)
  220. if (_googleApiClient != null && _googleApiClient.isConnected()) _googleApiClient.disconnect();
  221. _googleApiClient = null;
  222. }
  223.  
  224. /*
  225. public void signOut() {
  226. Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
  227. @Override
  228. public void onResult(Status status) {
  229. }
  230. });
  231. }
  232.  
  233. public void revokeAccess() {
  234. // FIXME: I don't know yet, but this may revoke access for all android devices
  235. Auth.GoogleSignInApi.revokeAccess(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
  236. @Override
  237. public void onResult(Status status) {
  238. }
  239. });
  240. }
  241. */
  242.  
  243. public void LogOut() {
  244. _loggedIn = false;
  245. saveToPrefs(); // don't clear refresh token as we may need again
  246. }
  247.  
  248.  
  249. // -------------------
  250. // API Calls
  251. // -------------------
  252.  
  253.  
  254. public void makeApiCall() {
  255. new Thread(new TestApiCall_Background()).start();
  256. }
  257.  
  258. private class TestApiCall_Background implements Runnable {
  259. public void run() {
  260.  
  261. FileAndErrorMsg fileAndErr = getFolderFromName_b("Many Files", null);
  262. if (fileAndErr.errorMsg != null) Log("getFolderFromName_b error: " + fileAndErr.errorMsg);
  263. else {
  264. FileListAndErrorMsg fileListAndErr = getFileListInFolder_b(fileAndErr.file);
  265. if (fileListAndErr.errorMsg != null)
  266. Log("getFileListInFolder_b error: " + fileListAndErr.errorMsg);
  267. else {
  268. Log("file count: " + fileListAndErr.fileList.size());
  269. for (File file : fileListAndErr.fileList) {
  270. //Log(file.getName());
  271. }
  272. }
  273. }
  274.  
  275. _handler.post(new Runnable() { public void run() {
  276. // Main thread
  277. } });
  278. }
  279. }
  280.  
  281. private FileAndErrorMsg getFolderFromName_b (String folderName, File parent) {
  282.  
  283. // parent can be null for top level
  284. // Working with folders: https://developers.google.com/drive/v3/web/folder
  285.  
  286. File folder = null;
  287. folderName = folderName.replace("'", "\'"); // escape '
  288. String q = String.format(Locale.US, "mimeType='application/vnd.google-apps.folder' and '%s' in parents and name='%s' and trashed=false", parent == null ? "root" : parent.getId(), folderName);
  289. String errorMsg = null;
  290. try {
  291. FileList result = _drive.files().list().setQ(q).setPageSize(1000).execute();
  292. int foundCount = 0;
  293. for (File file : result.getFiles()) {
  294. foundCount++;
  295. folder = file;
  296. }
  297. if (foundCount == 0) errorMsg = "Folder not found: " + folderName;
  298. else if (foundCount > 1) errorMsg = "More than one folder found with name (" + foundCount + "): " + folderName;
  299. }
  300. catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
  301. if (errorMsg != null) folder = null;
  302. return new FileAndErrorMsg(folder, errorMsg);
  303. }
  304.  
  305. private FileListAndErrorMsg getFileListInFolder_b (File folder) {
  306.  
  307. // folder can be null for top level; does not return subfolder names
  308. List<File> fileList = new ArrayList<File>();
  309. String q = String.format(Locale.US, "mimeType != 'application/vnd.google-apps.folder' and '%s' in parents and trashed=false", folder == null ? "root" : folder.getId());
  310. String errorMsg = null;
  311. try {
  312. String pageToken = null;
  313. do {
  314. FileList result = _drive.files().list().setQ(q).setPageSize(1000).setPageToken(pageToken).execute();
  315. fileList.addAll(result.getFiles());
  316. pageToken = result.getNextPageToken();
  317. } while (pageToken != null);
  318. }
  319. catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
  320. if (errorMsg != null) fileList = null;
  321. return new FileListAndErrorMsg(fileList, errorMsg);
  322. }
  323.  
  324.  
  325. // -------------------
  326. // Misc
  327. // -------------------
  328.  
  329. private void Log(String msg) {
  330. Log.v("ept", msg);
  331. }
  332.  
  333.  
  334. // -------------------
  335. // Load/Save Tokens
  336. // -------------------
  337.  
  338.  
  339. private void loadFromPrefs() {
  340. SharedPreferences pref = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
  341. _loggedIn = pref.getBoolean("GoogleLoggedIn", false);
  342. _refreshToken = pref.getString("GoogleRefreshToken", null);
  343. }
  344. private void saveToPrefs() {
  345. SharedPreferences.Editor editor = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE).edit();
  346. editor.putBoolean("GoogleLoggedIn", _loggedIn);
  347. editor.putString("GoogleRefreshToken", _refreshToken);
  348. editor.apply(); // async
  349.  
  350. }
  351.  
  352. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement