Handing authorisation issues with phone-to-Chrome.

Misc cleanup along the way.
This commit is contained in:
burke.davey
2011-05-08 21:44:16 +00:00
parent ea0873a8b2
commit 6b2b5e05d9
8 changed files with 144 additions and 126 deletions

View File

@@ -37,7 +37,8 @@
android:label="@string/app_name">
</activity>
<activity android:name=".ShareLinkActivity">
<activity android:name=".ShareLinkActivity"
android:theme="@style/Theme.Translucent">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<drawable name="translucent_background">#00000000</drawable>
</resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Translucent" parent="android:style/Theme.Translucent">
<item name="android:windowBackground">@drawable/translucent_background</item>
<item name="android:windowNoTitle">true</item>
<item name="android:colorForeground">#fff</item>
</style>
</resources>

View File

@@ -38,7 +38,6 @@ import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -46,15 +45,15 @@ import android.util.Log;
* AppEngine client. Handles auth.
*/
public class AppEngineClient {
private static final String TAG = "AppEngineClient";
static final String BASE_URL = "https://chrometophone.appspot.com";
static final String BASE_URL = "https://9.chrometophone.appspot.com";
private static final String AUTH_URL = BASE_URL + "/_ah/login";
private static final String AUTH_TOKEN_TYPE = "ah";
private final Context mContext;
private final String mAccountName;
private static final String TAG = "AppEngineClient";
public AppEngineClient(Context context, String accountName) {
this.mContext = context;
this.mAccountName = accountName;
@@ -70,11 +69,10 @@ public class AppEngineClient {
private HttpResponse makeRequestNoRetry(String urlPath, List<NameValuePair> params, boolean newToken)
throws Exception {
// Get auth token for account
Account account = new Account(mAccountName, "com.google");
String authToken = getAuthToken(mContext, account);
if (authToken == null) throw new PendingAuthException(mAccountName);
if (newToken) { // invalidate the cached token
AccountManager accountManager = AccountManager.get(mContext);
accountManager.invalidateAuthToken(account.type, authToken);
@@ -121,7 +119,7 @@ public class AppEngineClient {
return res;
}
private String getAuthToken(Context context, Account account) {
private String getAuthToken(Context context, Account account) throws PendingAuthException {
String authToken = null;
AccountManager accountManager = AccountManager.get(context);
try {
@@ -129,12 +127,8 @@ public class AppEngineClient {
accountManager.getAuthToken (account, AUTH_TOKEN_TYPE, false, null, null);
Bundle bundle = future.getResult();
authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
// User will be asked for "App Engine" permission.
if (authToken == null) {
// No auth token - will need to ask permission from user.
Intent intent = new Intent(SetupActivity.AUTH_PERMISSION_ACTION);
intent.putExtra("AccountManagerBundle", bundle);
context.sendBroadcast(intent);
throw new PendingAuthException(bundle);
}
} catch (OperationCanceledException e) {
Log.w(TAG, e.getMessage());
@@ -148,8 +142,14 @@ public class AppEngineClient {
public class PendingAuthException extends Exception {
private static final long serialVersionUID = 1L;
public PendingAuthException(String message) {
super(message);
private final Bundle mAccountManagerBundle;
public PendingAuthException(Bundle accountManagerBundle) {
super();
mAccountManagerBundle = accountManagerBundle;
}
public Bundle getAccountManagerBundle() {
return mAccountManagerBundle;
}
}
}

View File

@@ -27,9 +27,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.provider.Settings.Secure;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
/**
* Register/unregister with the Chrome to Phone App Engine server.
@@ -69,7 +67,10 @@ public class DeviceRegistrar {
}
context.sendBroadcast(updateUIIntent);
} catch (AppEngineClient.PendingAuthException pae) {
// Ignore - we'll reregister later
// Get setup activity to ask permission from user.
Intent intent = new Intent(SetupActivity.AUTH_PERMISSION_ACTION);
intent.putExtra("AccountManagerBundle", pae.getAccountManagerBundle());
context.sendBroadcast(intent);
} catch (Exception e) {
Log.w(TAG, "Registration error " + e.getMessage());
updateUIIntent.putExtra(STATUS_EXTRA, ERROR_STATUS);
@@ -86,20 +87,19 @@ public class DeviceRegistrar {
Intent updateUIIntent = new Intent("com.google.ctp.UPDATE_UI");
try {
HttpResponse res = makeRequest(context, deviceRegistrationID, UNREGISTER_PATH);
if (res.getStatusLine().getStatusCode() == 200) {
SharedPreferences settings = Prefs.get(context);
SharedPreferences.Editor editor = settings.edit();
editor.remove("deviceRegistrationID");
editor.commit();
updateUIIntent.putExtra(STATUS_EXTRA, UNREGISTERED_STATUS);
} else {
if (res.getStatusLine().getStatusCode() != 200) {
Log.w(TAG, "Unregistration error " +
String.valueOf(res.getStatusLine().getStatusCode()));
updateUIIntent.putExtra(STATUS_EXTRA, ERROR_STATUS);
}
} catch (Exception e) {
updateUIIntent.putExtra(STATUS_EXTRA, ERROR_STATUS);
Log.w(TAG, "Unegistration error " + e.getMessage());
Log.w(TAG, "Unregistration error " + e.getMessage());
} finally {
SharedPreferences settings = Prefs.get(context);
SharedPreferences.Editor editor = settings.edit();
editor.remove("deviceRegistrationID");
editor.remove("accountName");
editor.commit();
updateUIIntent.putExtra(STATUS_EXTRA, UNREGISTERED_STATUS);
}
// Update dialog activity

View File

@@ -29,6 +29,7 @@ import android.widget.ExpandableListView.OnChildClickListener;
*/
public class HistoryActivity extends Activity implements OnChildClickListener {
private static final int DIALOG_LINK_ACTION = 1;
private static final int SETUP_ACTIVITY_REQUEST_CODE = 1;
private ExpandableListView mList;
private HistoryExpandableListAdapter mListAdapter;
@@ -77,7 +78,8 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
return true;
}
case R.id.settings: {
startActivity(new Intent(this, SetupActivity.class));
startActivityForResult(new Intent(this, SetupActivity.class),
SETUP_ACTIVITY_REQUEST_CODE);
return true;
}
case R.id.help: {
@@ -90,6 +92,16 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
}
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
if (requestCode == SETUP_ACTIVITY_REQUEST_CODE) {
SharedPreferences prefs = Prefs.get(this);
if (prefs.getString("deviceRegistrationID", null) == null) {
finish(); // user asked to exit
}
}
}
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
mSelectedLink = mListAdapter.getLinkAtPosition(groupPosition, childPosition);

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* 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.google.android.apps.chrometophone;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
public class ShareLink implements Handler.Callback {
private static final String TOAST = "toast";
private static final String SEND_PATH = "/send";
private static ShareLink mInstance;
private final Handler mHandler;
private final Context mContext;
private ShareLink(Context context) {
mContext = context;
mHandler = new Handler(this);
}
public static synchronized ShareLink getInstance(Context context) {
if (mInstance == null) {
mInstance = new ShareLink(context);
}
return mInstance;
}
public void send(final String link) {
new Thread(new Runnable() {
public void run() {
sendToast(mContext.getString(R.string.sending_link_toast));
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("url", link));
params.add(new BasicNameValuePair("deviceName", "Chrome," +
(DeviceRegistrar.isTablet(mContext) ? "Phone" : "Tablet")));
SharedPreferences settings = Prefs.get(mContext);
final String accountName = settings.getString("accountName", null);
AppEngineClient client = new AppEngineClient(mContext, accountName);
HttpResponse res = client.makeRequest(SEND_PATH, params);
if (res.getStatusLine().getStatusCode() == 200) {
sendToast(mContext.getString(R.string.link_sent_toast));
} else {
sendToast(mContext.getString(R.string.link_not_sent_toast));
}
} catch (AppEngineClient.PendingAuthException e) {
sendToast(mContext.getString(R.string.link_not_sent_auth_toast));
} catch (Exception e) {
sendToast(mContext.getString(R.string.link_not_sent_toast));
}
}
}).start();
}
private void sendToast(String toastMessage) {
Message msg = new Message();
Bundle data = new Bundle();
data.putString(TOAST, toastMessage);
msg.setData(data);
mHandler.sendMessage(msg);
}
public boolean handleMessage(Message msg) {
Toast.makeText(mContext, msg.getData().getString(TOAST), Toast.LENGTH_LONG).show();
return true;
}
}

View File

@@ -16,18 +16,38 @@
package com.google.android.apps.chrometophone;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
/**
* Invoked when user selects "Share page" in the browser. Sends link
* to AppEngine server.
*/
public class ShareLinkActivity extends Activity {
public class ShareLinkActivity extends Activity implements Handler.Callback {
private static final int TOAST_MSG = 0;
private static final int START_ACTIVITY_MSG = 1;
private static final String SEND_PATH = "/send";
private boolean mPendingAuth = false;
private String mPendingLink;
private final Handler mHandler = new Handler(this);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -37,10 +57,76 @@ public class ShareLinkActivity extends Activity {
Pattern regex = Pattern.compile("http(s)?://.*"); // find the link
Matcher matcher = regex.matcher(text);
if (matcher.find()) {
String link = matcher.group();
ShareLink.getInstance(this).send(link);
mPendingAuth = false;
mPendingLink = matcher.group();
sendLink();
}
}
finish();
}
@Override
protected void onResume() {
super.onResume();
if (mPendingAuth) {
sendLink();
}
}
private void sendLink() {
new Thread(new Runnable() {
public void run() {
sendToast(getString(R.string.sending_link_toast));
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("url", mPendingLink));
params.add(new BasicNameValuePair("deviceName", "Chrome," +
(DeviceRegistrar.isTablet(ShareLinkActivity.this) ? "Phone" : "Tablet")));
SharedPreferences settings = Prefs.get(ShareLinkActivity.this);
final String accountName = settings.getString("accountName", null);
if (accountName == null) {
sendToast(getString(R.string.link_not_sent_auth_toast));
finish();
return;
}
AppEngineClient client = new AppEngineClient(ShareLinkActivity.this, accountName);
HttpResponse res = client.makeRequest(SEND_PATH, params);
if (res.getStatusLine().getStatusCode() == 200) {
sendToast(getString(R.string.link_sent_toast));
} else {
sendToast(getString(R.string.link_not_sent_toast));
}
finish();
} catch (AppEngineClient.PendingAuthException pae) {
Intent authIntent = (Intent) pae.getAccountManagerBundle().get(AccountManager.KEY_INTENT);
if (authIntent != null && !mPendingAuth) {
mPendingAuth = true;
mHandler.sendMessage(Message.obtain(mHandler, START_ACTIVITY_MSG, 0, 0, authIntent));
} else {
sendToast(getString(R.string.link_not_sent_auth_toast));
finish();
}
} catch (Exception e) {
sendToast(getString(R.string.link_not_sent_toast));
finish();
}
}
}).start();
}
private void sendToast(String toastMessage) {
mHandler.sendMessage(Message.obtain(mHandler, TOAST_MSG, 0, 0, toastMessage));
}
public boolean handleMessage(Message msg) {
if (msg.what == TOAST_MSG) {
Toast.makeText(this, (String) msg.obj, Toast.LENGTH_LONG).show();
} else if (msg.what == START_ACTIVITY_MSG) {
startActivity((Intent) msg.obj);
} else {
return false;
}
return true;
}
}