GoogleAccountLogin.java revision 539e2eced0f35144d7841477e5cdc2d8c521e82a
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.WebView; 39import android.webkit.WebViewClient; 40 41import java.util.ArrayList; 42 43public class GoogleAccountLogin extends Thread implements 44 AccountManagerCallback<Bundle>, OnCancelListener { 45 46 // Url for issuing the uber token. 47 private Uri ISSUE_AUTH_TOKEN_URL = Uri.parse( 48 "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false"); 49 // Url for signing into a particular service. 50 private final static Uri TOKEN_AUTH_URL = Uri.parse( 51 "https://www.google.com/accounts/TokenAuth"); 52 // Google account type 53 private final static String GOOGLE = "com.google"; 54 55 private final Activity mActivity; 56 private final Account mAccount; 57 private final WebView mWebView; 58 private Runnable mRunnable; 59 60 // SID and LSID retrieval process. 61 private String mSid; 62 private String mLsid; 63 private int mState; // {NONE(0), SID(1), LSID(2)} 64 65 GoogleAccountLogin(Activity activity, String name) { 66 mActivity = activity; 67 mAccount = new Account(name, GOOGLE); 68 mWebView = new WebView(mActivity); 69 mWebView.setWebViewClient(new WebViewClient() { 70 @Override 71 public boolean shouldOverrideUrlLoading(WebView view, String url) { 72 return false; 73 } 74 @Override 75 public void onPageFinished(WebView view, String url) { 76 done(); 77 } 78 }); 79 } 80 81 // Thread 82 @Override 83 public void run() { 84 String url = ISSUE_AUTH_TOKEN_URL.buildUpon() 85 .appendQueryParameter("SID", mSid) 86 .appendQueryParameter("LSID", mLsid) 87 .build().toString(); 88 // Intentionally not using Proxy. 89 AndroidHttpClient client = AndroidHttpClient.newInstance( 90 mWebView.getSettings().getUserAgentString()); 91 HttpPost request = new HttpPost(url); 92 93 String result = null; 94 try { 95 HttpResponse response = client.execute(request); 96 if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 97 done(); 98 return; 99 } 100 HttpEntity entity = response.getEntity(); 101 if (entity == null) { 102 done(); 103 return; 104 } 105 result = EntityUtils.toString(entity, "UTF-8"); 106 } catch (Exception e) { 107 request.abort(); 108 done(); 109 return; 110 } finally { 111 client.close(); 112 } 113 final String newUrl = TOKEN_AUTH_URL.buildUpon() 114 .appendQueryParameter("source", "android-browser") 115 .appendQueryParameter("auth", result) 116 .appendQueryParameter("continue", 117 BrowserSettings.getFactoryResetHomeUrl(mActivity)) 118 .build().toString(); 119 mActivity.runOnUiThread(new Runnable() { 120 @Override public void run() { 121 mWebView.loadUrl(newUrl); 122 } 123 }); 124 } 125 126 // AccountManager callbacks. 127 @Override 128 public void run(AccountManagerFuture<Bundle> value) { 129 try { 130 String id = value.getResult().getString( 131 AccountManager.KEY_AUTHTOKEN); 132 switch (mState) { 133 default: 134 case 0: 135 throw new IllegalStateException( 136 "Impossible to get into this state"); 137 case 1: 138 mSid = id; 139 mState = 2; // LSID 140 AccountManager.get(mActivity).getAuthToken( 141 mAccount, "LSID", null, mActivity, this, null); 142 break; 143 case 2: 144 mLsid = id; 145 this.start(); 146 break; 147 } 148 } catch (Exception e) { 149 // For all exceptions load the original signin page. 150 // TODO: toast login failed? 151 done(); 152 } 153 } 154 155 public void startLogin(Runnable runnable) { 156 mRunnable = runnable; 157 mState = 1; // SID 158 AccountManager.get(mActivity).getAuthToken( 159 mAccount, "SID", null, mActivity, this, null); 160 } 161 162 // Returns the account name passed in if the account exists, otherwise 163 // returns the default account. 164 public static String validateAccount(Context ctx, String name) { 165 Account[] accounts = getAccounts(ctx); 166 if (accounts.length == 0) { 167 return null; 168 } 169 if (name != null) { 170 // Make sure the account still exists. 171 for (Account a : accounts) { 172 if (a.name.equals(name)) { 173 return name; 174 } 175 } 176 } 177 // Return the first entry. 178 return accounts[0].name; 179 } 180 181 public static Account[] getAccounts(Context ctx) { 182 return AccountManager.get(ctx).getAccountsByType(GOOGLE); 183 } 184 185 // Used to indicate that the Browser should continue loading the main page. 186 // This can happen on success, error, or timeout. 187 private synchronized void done() { 188 if (mRunnable != null) { 189 mActivity.runOnUiThread(mRunnable); 190 mRunnable = null; 191 mWebView.destroy(); 192 } 193 } 194 195 // Called by the progress dialog on startup. 196 public void onCancel(DialogInterface unused) { 197 done(); 198 } 199} 200