/* * Copyright (C) 2008 The Android Open Source Project * * 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 org.awesomeapp.messenger; import android.app.Activity; import android.app.AlarmManager; import android.app.ProgressDialog; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.net.Uri.Builder; import android.os.Bundle; import android.os.Message; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; import org.awesomeapp.messenger.provider.Imps; import org.awesomeapp.messenger.ui.AddContactActivity; import org.awesomeapp.messenger.ui.legacy.ImPluginHelper; import org.awesomeapp.messenger.ui.LockScreenActivity; import org.awesomeapp.messenger.ui.legacy.SignInHelper; import org.awesomeapp.messenger.ui.legacy.SimpleAlertHandler; import org.awesomeapp.messenger.ui.legacy.ThemeableActivity; import org.awesomeapp.messenger.ui.onboarding.OnboardingActivity; import org.awesomeapp.messenger.util.SecureMediaStore; import org.ironrabbit.type.CustomTypefaceManager; import java.security.GeneralSecurityException; import java.util.List; import java.util.UUID; import info.guardianproject.cacheword.CacheWordHandler; import info.guardianproject.cacheword.ICacheWordSubscriber; import im.zom.messenger.R; import info.guardianproject.panic.Panic; import info.guardianproject.panic.PanicResponder; public class RouterActivity extends ThemeableActivity implements ICacheWordSubscriber { private static final String TAG = "RouterActivity"; private Cursor mProviderCursor; private ImApp mApp; private SimpleAlertHandler mHandler; private SignInHelper mSignInHelper; private boolean mDoSignIn = true; public static final String ACTION_LOCK_APP = "actionLockApp"; private static String EXTRA_DO_LOCK = "doLock"; private static String EXTRA_DO_SIGNIN = "doSignIn"; public static String EXTRA_ORIGINAL_INTENT = "originalIntent"; private ProgressDialog dialog; static final String[] PROVIDER_PROJECTION = { Imps.Provider._ID, Imps.Provider.NAME, Imps.Provider.FULLNAME, Imps.Provider.CATEGORY, Imps.Provider.ACTIVE_ACCOUNT_ID, Imps.Provider.ACTIVE_ACCOUNT_USERNAME, Imps.Provider.ACTIVE_ACCOUNT_PW, Imps.Provider.ACTIVE_ACCOUNT_LOCKED, Imps.Provider.ACTIVE_ACCOUNT_KEEP_SIGNED_IN, Imps.Provider.ACCOUNT_PRESENCE_STATUS, Imps.Provider.ACCOUNT_CONNECTION_STATUS, }; static final int PROVIDER_ID_COLUMN = 0; static final int PROVIDER_NAME_COLUMN = 1; static final int PROVIDER_FULLNAME_COLUMN = 2; static final int PROVIDER_CATEGORY_COLUMN = 3; static final int ACTIVE_ACCOUNT_ID_COLUMN = 4; static final int ACTIVE_ACCOUNT_USERNAME_COLUMN = 5; static final int ACTIVE_ACCOUNT_PW_COLUMN = 6; static final int ACTIVE_ACCOUNT_LOCKED = 7; static final int ACTIVE_ACCOUNT_KEEP_SIGNED_IN = 8; static final int ACCOUNT_PRESENCE_STATUS = 9; static final int ACCOUNT_CONNECTION_STATUS = 10; private CacheWordHandler mCacheWord = null; private boolean mDoLock; private final int REQUEST_LOCK_SCREEN = 9999; private final int REQUEST_HANDLE_LINK = REQUEST_LOCK_SCREEN+1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApp = (ImApp)getApplication(); mHandler = new MyHandler(this); Intent intent = getIntent(); mDoLock = ACTION_LOCK_APP.equals(intent.getAction()); if (mDoLock) { shutdownAndLock(this); return; } else if (Panic.isTriggerIntent(intent)) { if (PanicResponder.receivedTriggerFromConnectedApp(this)) { if (Preferences.uninstallApp()) { // lock and delete first for rapid response, then uninstall shutdownAndLock(this); PanicResponder.deleteAllAppData(this); Intent uninstall = new Intent(Intent.ACTION_DELETE); uninstall.setData(Uri.parse("package:" + getPackageName())); startActivity(uninstall); } else if (Preferences.clearAppData()) { // lock first for rapid response, then delete shutdownAndLock(this); PanicResponder.deleteAllAppData(this); } else if (Preferences.lockApp()) { shutdownAndLock(this); } // TODO add other responses here, paying attention to if/else order } else if (PanicResponder.shouldUseDefaultResponseToTrigger(this)) { if (Preferences.lockApp()) { shutdownAndLock(this); } } // this Intent should not trigger any more processing finish(); return; } mSignInHelper = new SignInHelper(this, mHandler); mDoSignIn = intent.getBooleanExtra(EXTRA_DO_SIGNIN, true); AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE); mCacheWord = new CacheWordHandler(this, (ICacheWordSubscriber)this); mCacheWord.connectToService(); // if we have an incoming contact, send it to the right place String scheme = intent.getScheme(); if(TextUtils.equals(scheme, "xmpp")) { intent.setClass(this, AddContactActivity.class); startActivity(intent); finish(); return; } } @SuppressWarnings("deprecation") private boolean cursorUnlocked() { try { Uri uri = Imps.Provider.CONTENT_URI_WITH_ACCOUNT; Builder builder = uri.buildUpon(); /** if (pKey != null) builder.appendQueryParameter(ImApp.CACHEWORD_PASSWORD_KEY, pKey); if (!allowCreate) builder = builder.appendQueryParameter(ImApp.NO_CREATE_KEY, "1"); */ uri = builder.build(); mProviderCursor = managedQuery(uri, PROVIDER_PROJECTION, Imps.Provider.CATEGORY + "=?" /* selection */, new String[] { ImApp.IMPS_CATEGORY } /* selection args */, Imps.Provider.DEFAULT_SORT_ORDER); if (mProviderCursor != null) { ImPluginHelper.getInstance(this).loadAvailablePlugins(); mProviderCursor.moveToFirst(); return true; } else { return false; } } catch (Exception e) { // Only complain if we thought this password should succeed Log.e(ImApp.LOG_TAG, e.getMessage(), e); Toast.makeText(this, getString(R.string.error_welcome_database), Toast.LENGTH_LONG).show(); finish(); // needs to be unlocked return false; } } @Override protected void onPause() { if (mHandler != null) mHandler.unregisterForBroadcastEvents(); super.onPause(); if (mCacheWord != null) mCacheWord.detach(); } @Override protected void onDestroy() { super.onDestroy(); if (mCacheWord != null) mCacheWord.disconnectFromService(); if (dialog != null) dialog.dismiss(); } @Override protected void onResume() { super.onResume(); if (mCacheWord != null) mCacheWord.reattach(); } private void doOnResume() { mHandler.registerForBroadcastEvents(); int countAvailable = accountsAvailable(); Intent intent = getIntent(); if (intent != null && intent.getAction() != null && !intent.getAction().equals(Intent.ACTION_MAIN)) { String action = intent.getAction(); Intent imUrlIntent = new Intent(this, ImUrlActivity.class); imUrlIntent.setAction(action); imUrlIntent.setType(intent.getType()); if (intent.getData() != null) imUrlIntent.setData(intent.getData()); // imUrlIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (intent.getExtras() != null) imUrlIntent.putExtras(intent.getExtras()); startActivityForResult(imUrlIntent, REQUEST_HANDLE_LINK); // setIntent(null); //finish(); } else if (countAvailable > 0) { if (mDoSignIn && mProviderCursor.moveToFirst()) { do { if (!mProviderCursor.isNull(ACTIVE_ACCOUNT_ID_COLUMN)) { int state = mProviderCursor.getInt(ACCOUNT_CONNECTION_STATUS); long accountId = mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN); if (mProviderCursor.getInt(ACTIVE_ACCOUNT_KEEP_SIGNED_IN) != 0) { signIn(accountId); } } } while (mProviderCursor.moveToNext()); } showMain(); } else { showOnboarding(); } } private void signIn(long accountId) { if (accountId == 0) { Log.w(TAG, "signIn: account id is 0, bail"); return; } boolean isAccountEditable = mProviderCursor.getInt(ACTIVE_ACCOUNT_LOCKED) == 0; if (isAccountEditable && mProviderCursor.isNull(ACTIVE_ACCOUNT_PW_COLUMN)) { // no password, edit the account //if (Log.isLoggable(TAG, Log.d)) // Log.i(TAG, "no pw for account " + accountId); Intent intent = getEditAccountIntent(); startActivity(intent); finish(); return; } long providerId = mProviderCursor.getLong(PROVIDER_ID_COLUMN); String password = mProviderCursor.getString(ACTIVE_ACCOUNT_PW_COLUMN); boolean isActive = false; // TODO(miron) mSignInHelper.signIn(password, providerId, accountId, isActive); } private boolean isSignedIn(Cursor cursor) { int connectionStatus = cursor.getInt(ACCOUNT_CONNECTION_STATUS); return connectionStatus == Imps.ConnectionStatus.ONLINE; } private int accountsAvailable() { if (mProviderCursor == null || !mProviderCursor.moveToFirst()) { return 0; } int count = 0; do { if (!mProviderCursor.isNull(ACTIVE_ACCOUNT_PW_COLUMN) && !mProviderCursor.isNull(ACTIVE_ACCOUNT_ID_COLUMN)) { count++; } } while (mProviderCursor.moveToNext()); return count; } Intent getEditAccountIntent() { Intent intent = new Intent(Intent.ACTION_EDIT, ContentUris.withAppendedId( Imps.Account.CONTENT_URI, mProviderCursor.getLong(ACTIVE_ACCOUNT_ID_COLUMN))); intent.putExtra("isSignedIn", isSignedIn(mProviderCursor)); intent.addCategory(getProviderCategory(mProviderCursor)); return intent; } private String getProviderCategory(Cursor cursor) { return cursor.getString(PROVIDER_CATEGORY_COLUMN); } private final static class MyHandler extends SimpleAlertHandler { public MyHandler(Activity activity) { super(activity); } @Override public void handleMessage(Message msg) { if (msg.what == ImApp.EVENT_CONNECTION_DISCONNECTED) { promptDisconnectedEvent(msg); } super.handleMessage(msg); } } @Override public void onCacheWordUninitialized() { Log.d(ImApp.LOG_TAG,"cache word uninit"); initTempPassphrase(); showOnboarding(); } void initTempPassphrase () { //set temporary passphrase try { String tempPassphrase = UUID.randomUUID().toString(); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); settings.edit().putString(ImApp.PREFERENCE_KEY_TEMP_PASS, tempPassphrase).apply(); mCacheWord.setPassphrase(tempPassphrase.toCharArray()); } catch (GeneralSecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } void showMain () { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); } void openChat(String username) { Intent intent = new Intent(this, MainActivity.class); intent.putExtra("username",username); startActivity(intent); finish(); } void showOnboarding () { //now show onboarding UI Intent intent = new Intent(this, OnboardingActivity.class); Intent returnIntent = getIntent(); returnIntent.putExtra(EXTRA_DO_SIGNIN, mDoSignIn); intent.putExtra(EXTRA_ORIGINAL_INTENT, returnIntent); startActivity(intent); finish(); } void showLockScreen() { Intent intent = new Intent(this, LockScreenActivity.class); Intent returnIntent = getIntent(); returnIntent.putExtra(EXTRA_DO_SIGNIN, mDoSignIn); intent.putExtra(EXTRA_ORIGINAL_INTENT, returnIntent); startActivityForResult(intent, REQUEST_LOCK_SCREEN); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_LOCK_SCREEN) { showMain(); return; } else if (requestCode == REQUEST_HANDLE_LINK) { if (data.hasExtra("newcontact")) { String username = data.getStringExtra("newcontact"); openChat(username); } } } finish(); } @Override public void onCacheWordLocked() { if (mDoLock) { Log.d(ImApp.LOG_TAG, "cacheword lock requested but already locked"); } else { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); if (settings.contains(ImApp.PREFERENCE_KEY_TEMP_PASS)) { try { mCacheWord.setPassphrase(settings.getString(ImApp.PREFERENCE_KEY_TEMP_PASS, null).toCharArray()); } catch (GeneralSecurityException e) { Log.d(ImApp.LOG_TAG, "couldn't open cacheword with temp password",e); showLockScreen(); } } else { showLockScreen(); } } } @Override public void onCacheWordOpened() { // mCacheWord.setTimeout(0); byte[] encryptionKey = mCacheWord.getEncryptionKey(); openEncryptedStores(encryptionKey); mApp.maybeInit(this); /* if (!mDoLock) { mHandler.postDelayed(new Runnable() { @Override public void run() { doOnResume(); } },1000); }*/ } public void shutdownAndLock(Context context) { mApp.forceStopImService(); finish(); } private boolean openEncryptedStores(byte[] key) { SecureMediaStore.init(this, key); if (cursorUnlocked()) { doOnResume(); return true; } else { return false; } } }