GoogleAccountLogin.java revision 97efb1e650b356d3fc81ff531544383362759d77
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.browser; 18 19import org.apache.http.Header; 20import org.apache.http.HeaderIterator; 21import org.apache.http.HttpEntity; 22import org.apache.http.HttpResponse; 23import org.apache.http.HttpStatus; 24import org.apache.http.client.methods.HttpPost; 25import org.apache.http.util.EntityUtils; 26 27import android.accounts.Account; 28import android.accounts.AccountManager; 29import android.accounts.AccountManagerCallback; 30import android.accounts.AccountManagerFuture; 31import android.app.Activity; 32import android.content.Context; 33import android.content.DialogInterface; 34import android.content.DialogInterface.OnCancelListener; 35import android.net.http.AndroidHttpClient; 36import android.net.Uri; 37import android.os.Bundle; 38import android.webkit.CookieManager; 39import android.webkit.WebView; 40import android.webkit.WebViewClient; 41 42import java.util.StringTokenizer; 43 44public class GoogleAccountLogin extends Thread implements 45 AccountManagerCallback<Bundle>, OnCancelListener { 46 47 // Url for issuing the uber token. 48 private Uri ISSUE_AUTH_TOKEN_URL = Uri.parse( 49 "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false"); 50 // Url for signing into a particular service. 51 private final static Uri TOKEN_AUTH_URL = Uri.parse( 52 "https://www.google.com/accounts/TokenAuth"); 53 // Google account type 54 private final static String GOOGLE = "com.google"; 55 56 private final Activity mActivity; 57 private final Account mAccount; 58 private final WebView mWebView; 59 private Runnable mRunnable; 60 61 // SID and LSID retrieval process. 62 private String mSid; 63 private String mLsid; 64 private int mState; // {NONE(0), SID(1), LSID(2)} 65 66 GoogleAccountLogin(Activity activity, String name) { 67 mActivity = activity; 68 mAccount = new Account(name, GOOGLE); 69 mWebView = new WebView(mActivity); 70 mWebView.setWebViewClient(new WebViewClient() { 71 @Override 72 public boolean shouldOverrideUrlLoading(WebView view, String url) { 73 return false; 74 } 75 @Override 76 public void onPageFinished(WebView view, String url) { 77 done(); 78 } 79 }); 80 } 81 82 // Thread 83 @Override 84 public void run() { 85 String url = ISSUE_AUTH_TOKEN_URL.buildUpon() 86 .appendQueryParameter("SID", mSid) 87 .appendQueryParameter("LSID", mLsid) 88 .build().toString(); 89 // Intentionally not using Proxy. 90 AndroidHttpClient client = AndroidHttpClient.newInstance( 91 mWebView.getSettings().getUserAgentString()); 92 HttpPost request = new HttpPost(url); 93 94 String result = null; 95 try { 96 HttpResponse response = client.execute(request); 97 if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 98 done(); 99 return; 100 } 101 HttpEntity entity = response.getEntity(); 102 if (entity == null) { 103 done(); 104 return; 105 } 106 result = EntityUtils.toString(entity, "UTF-8"); 107 } catch (Exception e) { 108 request.abort(); 109 done(); 110 return; 111 } finally { 112 client.close(); 113 } 114 final String newUrl = TOKEN_AUTH_URL.buildUpon() 115 .appendQueryParameter("source", "android-browser") 116 .appendQueryParameter("auth", result) 117 .appendQueryParameter("continue", 118 BrowserSettings.getFactoryResetHomeUrl(mActivity)) 119 .build().toString(); 120 mActivity.runOnUiThread(new Runnable() { 121 @Override public void run() { 122 mWebView.loadUrl(newUrl); 123 } 124 }); 125 } 126 127 // AccountManager callbacks. 128 @Override 129 public void run(AccountManagerFuture<Bundle> value) { 130 try { 131 String id = value.getResult().getString( 132 AccountManager.KEY_AUTHTOKEN); 133 switch (mState) { 134 default: 135 case 0: 136 throw new IllegalStateException( 137 "Impossible to get into this state"); 138 case 1: 139 mSid = id; 140 mState = 2; // LSID 141 AccountManager.get(mActivity).getAuthToken( 142 mAccount, "LSID", null, mActivity, this, null); 143 break; 144 case 2: 145 mLsid = id; 146 this.start(); 147 break; 148 } 149 } catch (Exception e) { 150 // For all exceptions load the original signin page. 151 // TODO: toast login failed? 152 done(); 153 } 154 } 155 156 public void startLogin(Runnable runnable) { 157 mRunnable = runnable; 158 mState = 1; // SID 159 AccountManager.get(mActivity).getAuthToken( 160 mAccount, "SID", null, mActivity, this, null); 161 } 162 163 // Returns the account name passed in if the account exists, otherwise 164 // returns the default account. 165 public static String validateAccount(Context ctx, String name) { 166 Account[] accounts = getAccounts(ctx); 167 if (accounts.length == 0) { 168 return null; 169 } 170 if (name != null) { 171 // Make sure the account still exists. 172 for (Account a : accounts) { 173 if (a.name.equals(name)) { 174 return name; 175 } 176 } 177 } 178 // Return the first entry. 179 return accounts[0].name; 180 } 181 182 public static Account[] getAccounts(Context ctx) { 183 return AccountManager.get(ctx).getAccountsByType(GOOGLE); 184 } 185 186 // Checks for the presence of the SID cookie on google.com. 187 public static boolean isLoggedIn() { 188 String cookies = CookieManager.getInstance().getCookie( 189 "http://www.google.com"); 190 if (cookies != null) { 191 StringTokenizer tokenizer = new StringTokenizer(cookies, ";"); 192 while (tokenizer.hasMoreTokens()) { 193 String cookie = tokenizer.nextToken().trim(); 194 if (cookie.startsWith("SID=")) { 195 return true; 196 } 197 } 198 } 199 return false; 200 } 201 202 // Used to indicate that the Browser should continue loading the main page. 203 // This can happen on success, error, or timeout. 204 private synchronized void done() { 205 if (mRunnable != null) { 206 mActivity.runOnUiThread(mRunnable); 207 mRunnable = null; 208 mWebView.destroy(); 209 } 210 } 211 212 // Called by the progress dialog on startup. 213 public void onCancel(DialogInterface unused) { 214 done(); 215 } 216} 217