diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 4ae0f4f..dc58757 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -37,7 +37,8 @@ android:label="@string/app_name"> - + diff --git a/android/res/values/colors.xml b/android/res/values/colors.xml new file mode 100644 index 0000000..ff0005b --- /dev/null +++ b/android/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #00000000 + diff --git a/android/res/values/styles.xml b/android/res/values/styles.xml new file mode 100644 index 0000000..919e383 --- /dev/null +++ b/android/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/android/src/com/google/android/apps/chrometophone/AppEngineClient.java b/android/src/com/google/android/apps/chrometophone/AppEngineClient.java index 4bcf071..d9380c4 100644 --- a/android/src/com/google/android/apps/chrometophone/AppEngineClient.java +++ b/android/src/com/google/android/apps/chrometophone/AppEngineClient.java @@ -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 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; } } } diff --git a/android/src/com/google/android/apps/chrometophone/DeviceRegistrar.java b/android/src/com/google/android/apps/chrometophone/DeviceRegistrar.java index 54c40e2..032b8af 100644 --- a/android/src/com/google/android/apps/chrometophone/DeviceRegistrar.java +++ b/android/src/com/google/android/apps/chrometophone/DeviceRegistrar.java @@ -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 diff --git a/android/src/com/google/android/apps/chrometophone/HistoryActivity.java b/android/src/com/google/android/apps/chrometophone/HistoryActivity.java index 1156372..e2edd8c 100644 --- a/android/src/com/google/android/apps/chrometophone/HistoryActivity.java +++ b/android/src/com/google/android/apps/chrometophone/HistoryActivity.java @@ -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); diff --git a/android/src/com/google/android/apps/chrometophone/ShareLink.java b/android/src/com/google/android/apps/chrometophone/ShareLink.java deleted file mode 100644 index 7dcf835..0000000 --- a/android/src/com/google/android/apps/chrometophone/ShareLink.java +++ /dev/null @@ -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 params = new ArrayList(); - 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; - } -} diff --git a/android/src/com/google/android/apps/chrometophone/ShareLinkActivity.java b/android/src/com/google/android/apps/chrometophone/ShareLinkActivity.java index 7c31ba0..12923a3 100644 --- a/android/src/com/google/android/apps/chrometophone/ShareLinkActivity.java +++ b/android/src/com/google/android/apps/chrometophone/ShareLinkActivity.java @@ -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 params = new ArrayList(); + 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; } }