Java tutorial
/******************************************************************************* * Copyright 2011 Google Inc. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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.capstonecontrol; import com.google.android.c2dm.C2DMessaging; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.ClientPNames; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.content.SharedPreferences.Editor; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; /** * Account selections activity - handles device registration and unregistration. */ public class AccountsActivity extends Activity { /** * Tag for logging. */ private static final String TAG = "AccountsActivity"; /** * Cookie name for authorization. */ private static final String AUTH_COOKIE_NAME = "SACSID"; /** * The selected position in the ListView of accounts. */ private int mAccountSelectedPosition = 0; /** * True if we are waiting for App Engine authorization. */ private boolean mPendingAuth = false; /** * The current context. */ private Context mContext = this; /** * Begins the activity. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedPreferences prefs = Util.getSharedPreferences(mContext); String deviceRegistrationID = prefs.getString(Util.DEVICE_REGISTRATION_ID, null); if (deviceRegistrationID == null) { // Show the 'connect' screen if we are not connected setScreenContent(R.layout.connect); } else { // Show the 'disconnect' screen if we are connected setScreenContent(R.layout.disconnect); } } /** * Resumes the activity. */ @Override protected void onResume() { super.onResume(); if (mPendingAuth) { mPendingAuth = false; String regId = C2DMessaging.getRegistrationId(mContext); if (regId != null && !"".equals(regId)) { DeviceRegistrar.registerOrUnregister(mContext, regId, true); } else { C2DMessaging.register(mContext, Setup.SENDER_ID); } } } // Manage UI Screens /** * Sets up the 'connect' screen content. */ private void setConnectScreenContent() { List<String> accounts = getGoogleAccounts(); if (accounts.size() == 0) { // Show a dialog and invoke the "Add Account" activity if requested AlertDialog.Builder builder = new AlertDialog.Builder(mContext); builder.setMessage(R.string.needs_account); builder.setPositiveButton(R.string.add_account, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Settings.ACTION_ADD_ACCOUNT)); } }); builder.setNegativeButton(R.string.skip, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.setIcon(android.R.drawable.stat_sys_warning); builder.setTitle(R.string.attention); builder.show(); } else { final ListView listView = (ListView) findViewById(R.id.select_account); listView.setAdapter(new ArrayAdapter<String>(mContext, R.layout.account, accounts)); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setItemChecked(mAccountSelectedPosition, true); final Button connectButton = (Button) findViewById(R.id.connect); connectButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { CapstoneControlActivity.userChanged = true; // Set "connecting" status SharedPreferences prefs = Util.getSharedPreferences(mContext); prefs.edit().putString(Util.CONNECTION_STATUS, Util.CONNECTING).commit(); // Get account name mAccountSelectedPosition = listView.getCheckedItemPosition(); TextView account = (TextView) listView.getChildAt(mAccountSelectedPosition); // Register register((String) account.getText()); // finish(); // clear the module list so that a new one will get found CapstoneControlActivity.modules.clear(); // instead of finish() go back to the AccountsActivity for // new login. CapstoneControlActivity.googleUserName = (String) account.getText(); Intent myIntent = new Intent(v.getContext(), SplashActivity.class); startActivity(myIntent); myIntent = new Intent(v.getContext(), CapstoneControlActivity.class); startActivity(myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); } }); } } /** * Sets up the 'disconnected' screen. */ private void setDisconnectScreenContent() { final SharedPreferences prefs = Util.getSharedPreferences(mContext); String accountName = prefs.getString(Util.ACCOUNT_NAME, "Unknown"); // Format the disconnect message with the currently connected account // name TextView disconnectText = (TextView) findViewById(R.id.disconnect_text); String message = getResources().getString(R.string.disconnect_text); String formatted = String.format(message, accountName); disconnectText.setText(formatted); final Button disconnectButton = (Button) findViewById(R.id.disconnect); disconnectButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Unregister C2DMessaging.unregister(mContext); // clear the module list so that a new one will get found CapstoneControlActivity.modules.clear(); // instead of finish() go back to the AccountsActivity for // new login. CapstoneControlActivity.userChanged = true; Intent myIntent = new Intent(v.getContext(), SplashActivity.class); startActivity(myIntent); myIntent = new Intent(v.getContext(), CapstoneControlActivity.class); startActivity(myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); } }); } /** * Sets the screen content based on the screen id. */ private void setScreenContent(int screenId) { setContentView(screenId); switch (screenId) { case R.layout.disconnect: setDisconnectScreenContent(); break; case R.layout.connect: setConnectScreenContent(); break; } } // Register and Unregister /** * Registers for C2DM messaging with the given account name. * * @param accountName * a String containing a Google account name */ private void register(final String accountName) { // Store the account name in shared preferences final SharedPreferences prefs = Util.getSharedPreferences(mContext); SharedPreferences.Editor editor = prefs.edit(); editor.putString(Util.ACCOUNT_NAME, accountName); editor.remove(Util.AUTH_COOKIE); editor.remove(Util.DEVICE_REGISTRATION_ID); editor.commit(); // Obtain an auth token and register final AccountManager mgr = AccountManager.get(mContext); Account[] accts = mgr.getAccountsByType("com.google"); for (Account acct : accts) { final Account account = acct; if (account.name.equals(accountName)) { if (Util.isDebug(mContext)) { // Use a fake cookie for the dev mode app engine server // The cookie has the form email:isAdmin:userId // We set the userId to be the same as the email String authCookie = "dev_appserver_login=" + accountName + ":false:" + accountName; prefs.edit().putString(Util.AUTH_COOKIE, authCookie).commit(); C2DMessaging.register(mContext, Setup.SENDER_ID); } else { // Get the auth token from the AccountManager and convert // it into a cookie for the appengine server final Activity activity = this; mgr.getAuthToken(account, "ah", null, activity, new AccountManagerCallback<Bundle>() { public void run(AccountManagerFuture<Bundle> future) { String authToken = getAuthToken(future); // Ensure the token is not expired by // invalidating it and // obtaining a new one mgr.invalidateAuthToken(account.type, authToken); mgr.getAuthToken(account, "ah", null, activity, new AccountManagerCallback<Bundle>() { public void run(AccountManagerFuture<Bundle> future) { String authToken = getAuthToken(future); // Convert the token into a // cookie for future use String authCookie = getAuthCookie(authToken); Editor editor = prefs.edit(); editor.putString(Util.AUTH_COOKIE, authCookie); editor.commit(); C2DMessaging.register(mContext, Setup.SENDER_ID); } }, null); } }, null); } break; } } } private String getAuthToken(AccountManagerFuture<Bundle> future) { try { Bundle authTokenBundle = future.getResult(); String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString(); return authToken; } catch (Exception e) { Log.w(TAG, "Got Exception " + e); return null; } } // Utility Methods /** * Retrieves the authorization cookie associated with the given token. This * method should only be used when running against a production appengine * backend (as opposed to a dev mode server). */ private String getAuthCookie(String authToken) { DefaultHttpClient httpClient = new DefaultHttpClient(); try { // Get SACSID cookie httpClient.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false); String uri = Setup.PROD_URL + "/_ah/login?continue=http://localhost/&auth=" + authToken; HttpGet method = new HttpGet(uri); HttpResponse res = httpClient.execute(method); StatusLine statusLine = res.getStatusLine(); int statusCode = statusLine.getStatusCode(); Header[] headers = res.getHeaders("Set-Cookie"); if (statusCode != 302 || headers.length == 0) { return null; } for (Cookie cookie : httpClient.getCookieStore().getCookies()) { if (AUTH_COOKIE_NAME.equals(cookie.getName())) { return AUTH_COOKIE_NAME + "=" + cookie.getValue(); } } } catch (IOException e) { Log.w(TAG, "Got IOException " + e); Log.w(TAG, Log.getStackTraceString(e)); } finally { httpClient.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true); } return null; } /** * Returns a list of registered Google account names. If no Google accounts * are registered on the device, a zero-length list is returned. */ private List<String> getGoogleAccounts() { ArrayList<String> result = new ArrayList<String>(); Account[] accounts = AccountManager.get(mContext).getAccounts(); for (Account account : accounts) { if (account.type.equals("com.google")) { result.add(account.name); } } return result; } }