1 /* 2 * Copyright (C) 2008 Esmertec AG. 3 * Copyright (C) 2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.android.im.app; 18 19 import com.android.im.IChatSession; 20 import com.android.im.IChatSessionManager; 21 import com.android.im.IConnectionListener; 22 import com.android.im.IImConnection; 23 import com.android.im.R; 24 import com.android.im.app.adapter.ConnectionListenerAdapter; 25 import com.android.im.engine.ImConnection; 26 import com.android.im.engine.ImErrorInfo; 27 import com.android.im.plugin.BrandingResourceIDs; 28 import com.android.im.service.ImServiceConstants; 29 30 import android.app.Activity; 31 import android.app.AlertDialog; 32 import android.content.ContentResolver; 33 import android.content.ContentUris; 34 import android.content.ContentValues; 35 import android.content.DialogInterface; 36 import android.content.Intent; 37 import android.content.res.Resources; 38 import android.database.Cursor; 39 import android.net.Uri; 40 import android.os.Bundle; 41 import android.os.RemoteException; 42 import android.os.Handler; 43 import android.provider.Im; 44 import android.util.Log; 45 import android.view.Menu; 46 import android.view.MenuItem; 47 import android.view.Window; 48 import android.widget.ImageView; 49 50 public class SigningInActivity extends Activity { 51 private static final String SYNC_SETTINGS_ACTION = "android.settings.SYNC_SETTINGS"; 52 private static final String SYNC_SETTINGS_CATEGORY = "android.intent.category.DEFAULT"; 53 54 private IImConnection mConn; 55 private IConnectionListener mListener; 56 private SimpleAlertHandler mHandler; 57 private ImApp mApp; 58 private long mProviderId; 59 private long mAccountId; 60 private String mProviderName; 61 62 private String mUserName; 63 private String mPassword; 64 65 private String mToAddress; 66 67 protected static final int ID_CANCEL_SIGNIN = Menu.FIRST + 1; 68 69 @Override onCreate(Bundle icicle)70 protected void onCreate(Bundle icicle) { 71 super.onCreate(icicle); 72 73 //setTheme(android.R.style.Theme_Dialog); 74 getWindow().requestFeature(Window.FEATURE_LEFT_ICON); 75 setContentView(R.layout.signing_in_activity); 76 Intent intent = getIntent(); 77 mToAddress = intent.getStringExtra(ImApp.EXTRA_INTENT_SEND_TO_USER); 78 79 Uri data = intent.getData(); 80 if (data == null) { 81 if(Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 82 log("Need account data to sign in"); 83 } 84 finish(); 85 return; 86 } 87 ContentResolver cr = getContentResolver(); 88 Cursor c = cr.query(data, null, null, null, null); 89 if (c == null) { 90 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 91 log("Query fail:" + data); 92 } 93 finish(); 94 return; 95 } 96 if (!c.moveToFirst()) { 97 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 98 log("No data for " + data); 99 } 100 c.close(); 101 finish(); 102 return; 103 } 104 105 mProviderId = c.getLong(c.getColumnIndexOrThrow(Im.Account.PROVIDER)); 106 mAccountId = c.getLong(c.getColumnIndexOrThrow(Im.Account._ID)); 107 mUserName = c.getString(c.getColumnIndexOrThrow(Im.Account.USERNAME)); 108 String pwExtra = intent.getStringExtra(ImApp.EXTRA_INTENT_PASSWORD); 109 mPassword = pwExtra != null ? pwExtra 110 : c.getString(c.getColumnIndexOrThrow(Im.Account.PASSWORD)); 111 final boolean isActive = c.getInt(c.getColumnIndexOrThrow(Im.Account.ACTIVE)) == 1; 112 113 c.close(); 114 mApp = ImApp.getApplication(this); 115 final ProviderDef provider = mApp.getProvider(mProviderId); 116 mProviderName = provider.mName; 117 118 BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); 119 getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, 120 brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_LOGO)); 121 122 setTitle(getResources().getString(R.string.signing_in_to, 123 provider.mFullName)); 124 125 ImageView splash = (ImageView)findViewById(R.id.splashscr); 126 splash.setImageDrawable(brandingRes.getDrawable( 127 BrandingResourceIDs.DRAWABLE_SPLASH_SCREEN)); 128 129 mHandler = new SimpleAlertHandler(this); 130 mListener = new MyConnectionListener(mHandler); 131 132 mApp.callWhenServiceConnected(mHandler, new Runnable() { 133 public void run() { 134 if (mApp.serviceConnected()) { 135 if (!isActive) { 136 activateAccount(mProviderId, mAccountId); 137 } 138 signInAccount(); 139 } 140 } 141 }); 142 143 // assume we can sign in successfully. 144 setResult(RESULT_OK); 145 } 146 147 @Override onRestart()148 protected void onRestart() { 149 super.onRestart(); 150 151 if (mApp.serviceConnected() && mApp.isBackgroundDataEnabled()) { 152 signInAccount(); 153 } else { 154 if(Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 155 log("onRestart: service disconnected or background data disabled..."); 156 } 157 setResult(RESULT_CANCELED); 158 finish(); 159 } 160 } 161 signInAccount()162 void signInAccount() { 163 try { 164 IImConnection conn = mApp.getConnection(mProviderId); 165 if (conn != null) { 166 mConn = conn; 167 // register listener before get state so that we won't miss 168 // any state change event. 169 conn.registerConnectionListener(mListener); 170 int state = conn.getState(); 171 if (state != ImConnection.LOGGING_IN) { 172 // already signed in or failed 173 conn.unregisterConnectionListener(mListener); 174 handleConnectionEvent(state, null); 175 } 176 } else { 177 if (mApp.isBackgroundDataEnabled()) { 178 mConn = mApp.createConnection(mProviderId); 179 mConn.registerConnectionListener(mListener); 180 mConn.login(mAccountId, mUserName, mPassword, true); 181 } else { 182 promptForBackgroundDataSetting(); 183 return; 184 } 185 } 186 187 } catch (RemoteException e) { 188 mHandler.showServiceErrorAlert(); 189 finish(); 190 } 191 } 192 activateAccount(long providerId, long accountId)193 private void activateAccount(long providerId, long accountId) { 194 // Update the active value. We restrict to only one active 195 // account per provider right now, so update all accounts of 196 // this provider to inactive first and then update this 197 // account to active. 198 ContentValues values = new ContentValues(1); 199 values.put(Im.Account.ACTIVE, 0); 200 ContentResolver cr = getContentResolver(); 201 cr.update(Im.Account.CONTENT_URI, values, 202 Im.Account.PROVIDER + "=" + providerId, null); 203 204 values.put(Im.Account.ACTIVE, 1); 205 cr.update(ContentUris.withAppendedId(Im.Account.CONTENT_URI, accountId), 206 values, null, null); 207 } 208 209 @Override onStop()210 protected void onStop() { 211 super.onStop(); 212 213 if (mApp != null) { 214 mApp.removePendingCall(mHandler); 215 } 216 if (mConn != null) { 217 try { 218 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 219 log("unregisterConnectonListener"); 220 } 221 mConn.unregisterConnectionListener(mListener); 222 } catch (RemoteException e) { 223 Log.w(ImApp.LOG_TAG, "<SigningInActivity> Connection disappeared!"); 224 } 225 } 226 // When background data is enabled, we don't want this activity in the backlist 227 // so we always call finish() when we leave signing in screen. Otherwise, we 228 // don't finish since we need to keep signing in if user choose to enable background. 229 if (mApp.isBackgroundDataEnabled()) { 230 finish(); 231 } 232 } 233 234 @Override onCreateOptionsMenu(Menu menu)235 public boolean onCreateOptionsMenu(Menu menu) { 236 menu.add(0, ID_CANCEL_SIGNIN, 0, R.string.menu_cancel_signin) 237 .setIcon(android.R.drawable.ic_menu_close_clear_cancel); 238 239 return true; 240 } 241 242 @Override onOptionsItemSelected(MenuItem item)243 public boolean onOptionsItemSelected(MenuItem item) { 244 if (item.getItemId() == ID_CANCEL_SIGNIN) { 245 if (mConn != null) { 246 try { 247 if (mConn.getState() == ImConnection.LOGGING_IN) { 248 if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { 249 log("Cancelling sign in"); 250 } 251 mConn.logout(); 252 finish(); 253 } 254 } catch (RemoteException e) { 255 Log.w(ImApp.LOG_TAG, "<SigningInActivity> Connection disappeared!"); 256 } 257 } 258 return true; 259 } else { 260 return super.onOptionsItemSelected(item); 261 } 262 } 263 264 /** 265 * Popup a dialog to ask the user whether he/she wants to enable 266 * background connection to continue. If yes, enable the setting 267 * and broadcast the change. Otherwise, quit the signing in window 268 * immediately. 269 */ promptForBackgroundDataSetting()270 private void promptForBackgroundDataSetting() { 271 new AlertDialog.Builder(SigningInActivity.this) 272 .setTitle(R.string.bg_data_prompt_title) 273 .setIcon(android.R.drawable.ic_dialog_alert) 274 .setMessage(getString(R.string.bg_data_prompt_message, mProviderName)) 275 .setPositiveButton(R.string.bg_data_prompt_ok, new DialogInterface.OnClickListener() { 276 public void onClick(DialogInterface dialog, int whichButton) { 277 Intent intent = new Intent(SYNC_SETTINGS_ACTION); 278 intent.addCategory(SYNC_SETTINGS_CATEGORY); 279 startActivity(intent); 280 } 281 }) 282 .setNegativeButton(R.string.bg_data_prompt_cancel, 283 new DialogInterface.OnClickListener() { 284 public void onClick(DialogInterface dialog, int whichButton) { 285 setResult(RESULT_CANCELED); 286 finish(); 287 } 288 }) 289 .show(); 290 } 291 handleConnectionEvent(int state, ImErrorInfo error)292 void handleConnectionEvent(int state, ImErrorInfo error) { 293 if (isFinishing()) { 294 return; 295 } 296 297 if (state == ImConnection.LOGGED_IN) { 298 // sign in successfully, finish and switch to contact list 299 finish(); 300 try { 301 Intent intent; 302 long accountId = mConn.getAccountId(); 303 304 if (mToAddress != null) { 305 IChatSessionManager manager = mConn.getChatSessionManager(); 306 IChatSession session = manager.getChatSession(mToAddress); 307 if(session == null) { 308 session = manager.createChatSession(mToAddress); 309 } 310 Uri data = ContentUris.withAppendedId(Im.Chats.CONTENT_URI, session.getId()); 311 intent = new Intent(Intent.ACTION_VIEW, data); 312 intent.putExtra("from", mToAddress); 313 intent.putExtra("providerId", mProviderId); 314 intent.putExtra("accountId", accountId); 315 intent.addCategory(ImApp.IMPS_CATEGORY); 316 317 } else { 318 intent = new Intent(this, ContactListActivity.class); 319 intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, accountId); 320 } 321 startActivity(intent); 322 } catch (RemoteException e) { 323 // Ouch! Service died! We'll just disappear. 324 Log.w(ImApp.LOG_TAG, "<SigningInActivity> Connection disappeared while signing in!"); 325 } 326 } else if (state == ImConnection.DISCONNECTED) { 327 // sign in failed 328 Resources r = getResources(); 329 new AlertDialog.Builder(this) 330 .setTitle(R.string.error) 331 .setMessage(r.getString(R.string.login_service_failed, mProviderName, 332 error == null? "": ErrorResUtils.getErrorRes(r, error.getCode()))) 333 .setPositiveButton(R.string.ok, 334 new DialogInterface.OnClickListener() { 335 public void onClick(DialogInterface dialog, int whichButton) { 336 setResult(RESULT_CANCELED); 337 finish(); 338 } 339 }) 340 .setCancelable(false) 341 .show(); 342 } 343 } 344 log(String msg)345 private static final void log(String msg) { 346 Log.d(ImApp.LOG_TAG, "<SigningInActivity>" + msg); 347 } 348 349 private final class MyConnectionListener extends ConnectionListenerAdapter { MyConnectionListener(Handler handler)350 MyConnectionListener(Handler handler) { 351 super(handler); 352 } 353 354 @Override onConnectionStateChange(IImConnection connection, int state, ImErrorInfo error)355 public void onConnectionStateChange(IImConnection connection, 356 int state, ImErrorInfo error) { 357 handleConnectionEvent(state, error); 358 } 359 } 360 } 361