/* * Copyright (C) 2007-2008 Esmertec AG. Copyright (C) 2007-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.service; import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.net.NetworkInfo; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; import net.java.otr4j.OtrEngineListener; import net.java.otr4j.OtrKeyManagerListener; import net.java.otr4j.OtrPolicy; import net.java.otr4j.session.SessionID; import org.awesomeapp.messenger.ImApp; import org.awesomeapp.messenger.MainActivity; import org.awesomeapp.messenger.Preferences; import org.awesomeapp.messenger.crypto.IOtrKeyManager; import org.awesomeapp.messenger.crypto.otr.OtrAndroidKeyManagerImpl; import org.awesomeapp.messenger.crypto.otr.OtrChatManager; import org.awesomeapp.messenger.crypto.otr.OtrDebugLogger; import org.awesomeapp.messenger.model.ConnectionFactory; import org.awesomeapp.messenger.model.ConnectionListener; import org.awesomeapp.messenger.model.ImConnection; import org.awesomeapp.messenger.model.ImErrorInfo; import org.awesomeapp.messenger.model.ImException; import org.awesomeapp.messenger.plugin.ImPluginInfo; import org.awesomeapp.messenger.provider.Imps; import org.awesomeapp.messenger.service.adapters.ImConnectionAdapter; import org.awesomeapp.messenger.ui.legacy.DummyActivity; import org.awesomeapp.messenger.ui.legacy.ImPluginHelper; import org.awesomeapp.messenger.service.NetworkConnectivityReceiver.State; import org.awesomeapp.messenger.util.Debug; import org.awesomeapp.messenger.util.LogCleaner; import org.awesomeapp.messenger.util.SecureMediaStore; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Map; import info.guardianproject.cacheword.CacheWordHandler; import info.guardianproject.cacheword.ICacheWordSubscriber; import im.zom.messenger.R; public class RemoteImService extends Service implements OtrEngineListener, ImService, ICacheWordSubscriber { private static final String PREV_CONNECTIONS_TRAIL_TAG = "prev_connections"; private static final String CONNECTIONS_TRAIL_TAG = "connections"; private static final String LAST_SWIPE_TRAIL_TAG = "last_swipe"; private static final String SERVICE_DESTROY_TRAIL_TAG = "service_destroy"; private static final String PREV_SERVICE_CREATE_TRAIL_TAG = "prev_service_create"; private static final String SERVICE_CREATE_TRAIL_KEY = "service_create"; private static final String[] ACCOUNT_PROJECTION = { Imps.Account._ID, Imps.Account.PROVIDER, Imps.Account.USERNAME, Imps.Account.PASSWORD, Imps.Account.ACTIVE, Imps.Account.KEEP_SIGNED_IN}; // TODO why aren't these Imps.Account.* values? private static final int ACCOUNT_ID_COLUMN = 0; private static final int ACCOUNT_PROVIDER_COLUMN = 1; private static final int ACCOUNT_USERNAME_COLUMN = 2; private static final int ACCOUNT_PASSOWRD_COLUMN = 3; private static final int ACCOUNT_ACTIVE = 4; private static final int ACCOUNT_KEEP_SIGNED_IN = 5; private static final int EVENT_SHOW_TOAST = 100; private StatusBarNotifier mStatusBarNotifier; private Handler mServiceHandler; private int mNetworkType; private boolean mNeedCheckAutoLogin; //private SettingsMonitor mSettingsMonitor; private OtrChatManager mOtrChatManager; private ImPluginHelper mPluginHelper; private Hashtable<Long, ImConnectionAdapter> mConnections; private Hashtable<String, ImConnectionAdapter> mConnectionsByUser; private Handler mHandler; final RemoteCallbackList<IConnectionCreationListener> mRemoteListeners = new RemoteCallbackList<IConnectionCreationListener>(); public long mHeartbeatInterval; private WakeLock mWakeLock; private NetworkConnectivityReceiver.State mNetworkState; private CacheWordHandler mCacheWord = null; private NotificationManager mNotifyManager; NotificationCompat.Builder mNotifyBuilder; private int mNumNotify = 0; private final static int notifyId = 7777; private static final String TAG = "ZomService"; public long getHeartbeatInterval() { return mHeartbeatInterval; } public static void debug(String msg) { LogCleaner.debug(TAG, msg); // Log.d(TAG, msg); } public static void debug(String msg, Exception e) { LogCleaner.error(TAG, msg, e); } private void updateOtrPolicy () { int otrPolicy = convertPolicy(); mOtrChatManager.setPolicy(otrPolicy); } private synchronized OtrChatManager initOtrChatManager() { int otrPolicy = convertPolicy(); if (mOtrChatManager == null) { try { OtrAndroidKeyManagerImpl otrKeyManager = OtrAndroidKeyManagerImpl.getInstance(this); if (otrKeyManager != null) { mOtrChatManager = OtrChatManager.getInstance(otrPolicy, this, otrKeyManager); mOtrChatManager.addOtrEngineListener(this); otrKeyManager.addListener(new OtrKeyManagerListener() { public void verificationStatusChanged(SessionID session) { boolean isVerified = mOtrChatManager.getKeyManager().isVerified(session); String msg = session + ": verification status=" + isVerified; OtrDebugLogger.log(msg); } public void remoteVerifiedUs(SessionID session) { String msg = session + ": remote verified us"; OtrDebugLogger.log(msg); showToast(getString(R.string.remote_verified_us),Toast.LENGTH_SHORT); // if (!isRemoteKeyVerified(session)) // showWarning(session, mContext.getApplicationContext().getString(R.string.remote_verified_us)); } }); } } catch (Exception e) { OtrDebugLogger.log("unable to init OTR manager", e); } } else { mOtrChatManager.setPolicy(otrPolicy); } return mOtrChatManager; } private int convertPolicy() { int otrPolicy = OtrPolicy.OPPORTUNISTIC; String otrModeSelect = Preferences.getOtrMode(); if (otrModeSelect.equals("auto")) { otrPolicy = OtrPolicy.OPPORTUNISTIC; } else if (otrModeSelect.equals("disabled")) { otrPolicy = OtrPolicy.NEVER; } else if (otrModeSelect.equals("force")) { otrPolicy = OtrPolicy.OTRL_POLICY_ALWAYS; } else if (otrModeSelect.equals("requested")) { otrPolicy = OtrPolicy.OTRL_POLICY_MANUAL; } return otrPolicy; } @Override public void onCreate() { debug("ImService started"); final String prev = Debug.getTrail(this, SERVICE_CREATE_TRAIL_KEY); if (prev != null) Debug.recordTrail(this, PREV_SERVICE_CREATE_TRAIL_TAG, prev); Debug.recordTrail(this, SERVICE_CREATE_TRAIL_KEY, new Date()); final String prevConnections = Debug.getTrail(this, CONNECTIONS_TRAIL_TAG); if (prevConnections != null) Debug.recordTrail(this, PREV_CONNECTIONS_TRAIL_TAG, prevConnections); Debug.recordTrail(this, CONNECTIONS_TRAIL_TAG, "0"); mConnections = new Hashtable<Long, ImConnectionAdapter>(); mConnectionsByUser = new Hashtable<String, ImConnectionAdapter>(); mHandler = new Handler(); Debug.onServiceStart(); //startForegroundCompat(); PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "IM_WAKELOCK"); // Clear all account statii to logged-out, since we just got started and we don't want // leftovers from any previous crash. clearConnectionStatii(); mStatusBarNotifier = new StatusBarNotifier(this); mServiceHandler = new ServiceHandler(); mPluginHelper = ImPluginHelper.getInstance(this); mPluginHelper.loadAvailablePlugins(); // Have the heartbeat start autoLogin, unless onStart turns this off mNeedCheckAutoLogin = true; HeartbeatService.startBeating(getApplicationContext()); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); startForeground(notifyId, getForegroundNotification()); } private void checkUpgrade () { ImApp app = ((ImApp)getApplication()); if (app.needsAccountUpgrade()) { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0); getStatusBarNotifier().notify(getString(R.string.upgrade_action), getString(R.string.upgrade_desc),getString(R.string.upgrade_desc),notificationIntent, false); } } private void connectToCacheWord () { if (mCacheWord == null) { mCacheWord = new CacheWordHandler(this, (ICacheWordSubscriber) this); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); mCacheWord.connectToService(); } } private Notification getForegroundNotification() { mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);; mNotifyBuilder = new NotificationCompat.Builder(this) .setContentTitle(getString(R.string.app_name)) .setSmallIcon(R.drawable.notify_zom); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { mNotifyBuilder.setPriority(Notification.PRIORITY_MIN); } mNotifyBuilder.setOngoing(true); mNotifyBuilder.setWhen(System.currentTimeMillis()); Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0); mNotifyBuilder.setContentIntent(launchIntent); mNotifyBuilder.setContentText(getString(R.string.app_unlocked)); return mNotifyBuilder.build(); } public void sendHeartbeat() { Debug.onHeartbeat(); try { if (mNeedCheckAutoLogin && mNetworkState != NetworkConnectivityReceiver.State.NOT_CONNECTED) { debug("autoLogin from heartbeat"); mNeedCheckAutoLogin = !autoLogin();; } mHeartbeatInterval = Preferences.getHeartbeatInterval(); debug("heartbeat interval: " + mHeartbeatInterval); for (ImConnectionAdapter conn : mConnections.values()) { conn.sendHeartbeat(); } } finally { return; } } @Override public int onStartCommand(Intent intent, int flags, int startId) { //if the service restarted, then we need to reconnect/reinit to cacheword // if ((flags & START_FLAG_REDELIVERY)!=0) // if crash restart.. connectToCacheWord(); if (intent != null) { if (intent.hasExtra(ImServiceConstants.EXTRA_CHECK_AUTO_LOGIN)) mNeedCheckAutoLogin = intent.getBooleanExtra(ImServiceConstants.EXTRA_CHECK_AUTO_LOGIN, false); if (HeartbeatService.HEARTBEAT_ACTION.equals(intent.getAction())) { // Log.d(TAG, "HEARTBEAT"); if (!mWakeLock.isHeld()) { try { mWakeLock.acquire(); sendHeartbeat(); } finally { mWakeLock.release(); } } return START_REDELIVER_INTENT; } if (HeartbeatService.NETWORK_STATE_ACTION.equals(intent.getAction())) { NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(HeartbeatService.NETWORK_INFO_EXTRA); NetworkConnectivityReceiver.State networkState = State.values()[intent.getIntExtra(HeartbeatService.NETWORK_STATE_EXTRA, 0)]; if (!mWakeLock.isHeld()) { try { mWakeLock.acquire(); networkStateChanged(networkInfo, networkState); } finally { mWakeLock.release(); } } else { networkStateChanged(networkInfo, networkState); } return START_REDELIVER_INTENT; } if (ImServiceConstants.EXTRA_CHECK_SHUTDOWN.equals((intent.getAction()))) { shutdown(); stopSelf(); } } debug("ImService.onStart, checkAutoLogin=" + mNeedCheckAutoLogin + " intent =" + intent + " startId =" + startId); if (mNeedCheckAutoLogin && mNetworkState != NetworkConnectivityReceiver.State.NOT_CONNECTED) { debug("autoLogin from heartbeat"); mNeedCheckAutoLogin = !autoLogin();; } return START_STICKY; } @Override public void onLowMemory() { } @Override public void onTrimMemory(int level) { /** * TRIM_MEMORY_COMPLETE, TRIM_MEMORY_MODERATE, TRIM_MEMORY_BACKGROUND, TRIM_MEMORY_UI_HIDDEN, TRIM_MEMORY_RUNNING_CRITICAL, TRIM_MEMORY_RUNNING_LOW, or TRIM_MEMORY_RUNNING_MODERATE. */ switch (level) { case TRIM_MEMORY_BACKGROUND: case TRIM_MEMORY_UI_HIDDEN: Log.w(TAG,"in the background/no UI, so we should be efficient"); return; case TRIM_MEMORY_RUNNING_LOW: case TRIM_MEMORY_RUNNING_CRITICAL: Log.w(TAG,"memory is low or critical"); return; } } private void clearConnectionStatii() { ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(2); values.put(Imps.AccountStatus.PRESENCE_STATUS, Imps.Presence.OFFLINE); values.put(Imps.AccountStatus.CONNECTION_STATUS, Imps.ConnectionStatus.OFFLINE); try { //insert on the "account_status" uri actually replaces the existing value cr.update(Imps.AccountStatus.CONTENT_URI, values, null, null); } catch (Exception e) { //this can throw NPE on restart sometimes if database has not been unlocked debug("database is not unlocked yet. caught NPE from mDbHelper in ImpsProvider"); } } private boolean autoLogin() { /** // Try empty passphrase. We can't autologin if this fails. if (!Imps.setEmptyPassphrase(this, true)) { debug("Cannot autologin with non-empty passphrase"); return false; } */ debug("Scanning accounts and login automatically"); ContentResolver resolver = getContentResolver(); String where = "";//Imps.Account.KEEP_SIGNED_IN + "=1 AND " + Imps.Account.ACTIVE + "=1"; Cursor cursor = resolver.query(Imps.Account.CONTENT_URI, ACCOUNT_PROJECTION, where, null, null); if (cursor == null) { Log.w(TAG, "Can't query account!"); return false; } boolean didAutoLogin = false; while (cursor.moveToNext()) { long accountId = cursor.getLong(ACCOUNT_ID_COLUMN); long providerId = cursor.getLong(ACCOUNT_PROVIDER_COLUMN); int isActive = cursor.getInt(ACCOUNT_ACTIVE); int isKeepSignedIn = cursor.getInt(ACCOUNT_KEEP_SIGNED_IN); if (isActive == 1 && isKeepSignedIn == 1) { IImConnection conn = mConnections.get(providerId); if (conn == null) conn = do_createConnection(providerId, accountId); try { if (conn.getState() != ImConnection.LOGGED_IN) { try { conn.login(null, true, true); } catch (RemoteException e) { Log.w(TAG, "Logging error while automatically login: " + accountId); } } } catch (Exception e) { Log.d(ImApp.LOG_TAG, "error auto logging into ImConnection: " + accountId); } didAutoLogin = true; } } cursor.close(); return didAutoLogin; } private Map<String, String> loadProviderSettings(long providerId) { ContentResolver cr = getContentResolver(); Map<String, String> settings = Imps.ProviderSettings.queryProviderSettings(cr, providerId); return settings; } @Override public void onDestroy() { shutdown(); } private void shutdown () { Debug.recordTrail(this, SERVICE_DESTROY_TRAIL_TAG, new Date()); HeartbeatService.stopBeating(getApplicationContext()); Log.w(TAG, "ImService stopped."); for (ImConnectionAdapter conn : mConnections.values()) { if (conn.getState() == ImConnection.LOGGED_IN) conn.logout(); } stopForeground(true); /* ignore unmount errors and quit ASAP. Threads actively using the VFS will * cause IOCipher's VirtualFileSystem.unmount() to throw an IllegalStateException */ try { if (SecureMediaStore.isMounted()) SecureMediaStore.unmount(); } catch (IllegalStateException e) { Log.e(ImApp.LOG_TAG,"there was a problem unmoiunt secure media store: " + e.getMessage()); } if (mCacheWord != null && (!mCacheWord.isLocked())) { mCacheWord.lock(); mCacheWord.disconnectFromService(); } } @Override public IBinder onBind(Intent intent) { return mBinder; } public void showToast(CharSequence text, int duration) { Message msg = Message.obtain(mServiceHandler, EVENT_SHOW_TOAST, duration, 0, text); msg.sendToTarget(); } public StatusBarNotifier getStatusBarNotifier() { return mStatusBarNotifier; } public OtrChatManager getOtrChatManager() { return initOtrChatManager(); } public void scheduleReconnect(long delay) { if (!isNetworkAvailable()) { // Don't schedule reconnect if no network available. We will try to // reconnect when network state become CONNECTED. return; } mServiceHandler.postDelayed(new Runnable() { public void run() { reestablishConnections(); } }, delay); } private IImConnection do_createConnection(long providerId, long accountId) { if (providerId == -1) return null; Map<String, String> settings = loadProviderSettings(providerId); //make sure OTR is init'd before you create your first connection initOtrChatManager(); ConnectionFactory factory = ConnectionFactory.getInstance(); try { ImConnection conn = factory.createConnection(settings, this); conn.initUser(providerId, accountId); ImConnectionAdapter imConnectionAdapter = new ImConnectionAdapter(providerId, accountId, conn, this); conn.addConnectionListener(new ConnectionListener() { @Override public void onStateChanged(int state, ImErrorInfo error) { } @Override public void onUserPresenceUpdated() { } @Override public void onUpdatePresenceError(ImErrorInfo error) { } }); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(Imps.ProviderSettings.CONTENT_URI,new String[] {Imps.ProviderSettings.NAME, Imps.ProviderSettings.VALUE},Imps.ProviderSettings.PROVIDER + "=?",new String[] { Long.toString(providerId)},null); if (cursor == null) throw new ImException ("unable to query the provider settings"); Imps.ProviderSettings.QueryMap providerSettings = new Imps.ProviderSettings.QueryMap( cursor, contentResolver, providerId, false, null); String userName = Imps.Account.getUserName(contentResolver, accountId); String domain = providerSettings.getDomain(); providerSettings.close(); mConnections.put(providerId, imConnectionAdapter); mConnectionsByUser.put(imConnectionAdapter.getLoginUser().getAddress().getBareAddress(),imConnectionAdapter); Debug.recordTrail(this, CONNECTIONS_TRAIL_TAG, "" + mConnections.size()); synchronized (mRemoteListeners) { try { final int N = mRemoteListeners.beginBroadcast(); for (int i = 0; i < N; i++) { IConnectionCreationListener listener = mRemoteListeners.getBroadcastItem(i); try { listener.onConnectionCreated(imConnectionAdapter); } catch (RemoteException e) { // The RemoteCallbackList will take care of removing the // dead listeners. } } } finally { mRemoteListeners.finishBroadcast(); } } return imConnectionAdapter; } catch (ImException e) { debug("Error creating connection", e); return null; } } public void removeConnection(ImConnectionAdapter connection) { mConnections.remove(connection); mConnectionsByUser.remove(connection.getLoginUser()); if (mConnections.size() == 0) if (Preferences.getUseForegroundPriority()) stopForeground(true); } boolean isNetworkAvailable () { return mNetworkState == State.CONNECTED; } void networkStateChanged(NetworkInfo networkInfo, NetworkConnectivityReceiver.State networkState) { int networkType = networkInfo != null ? networkInfo.getType() : -1; debug("networkStateChanged: type=" + networkInfo + " state=" + networkState); boolean networkChanged = false; if (mNetworkType != networkType || mNetworkState != networkState) { mNetworkState = networkState; mNetworkType = networkType; networkChanged = true; for (ImConnectionAdapter conn : mConnections.values()) conn.networkTypeChanged(); //update the notification if (mNotifyBuilder != null) { String message = ""; if (!isNetworkAvailable()) { message = getString(R.string.error_suspended_connection); mNotifyBuilder.setSmallIcon(R.drawable.notify_zom); } else { message = getString(R.string.app_unlocked); mNotifyBuilder.setSmallIcon(R.drawable.notify_zom); } mNotifyBuilder.setContentText(message); // Because the ID remains unchanged, the existing notification is // updated. mNotifyManager.notify( notifyId, mNotifyBuilder.build()); } } if (isNetworkAvailable()) { boolean reConnd = reestablishConnections(); if (!reConnd) { if (mNeedCheckAutoLogin) { mNeedCheckAutoLogin = !autoLogin(); } } } else { suspendConnections(); } } // package private for inner class access boolean reestablishConnections() { for (ImConnectionAdapter conn : mConnections.values()) { int connState = conn.getState(); if (connState == ImConnection.SUSPENDED) { conn.reestablishSession(); } } return mConnections.values().size() > 0; } private void suspendConnections() { for (ImConnectionAdapter conn : mConnections.values()) { if (conn.getState() == ImConnection.LOGGED_IN || conn.getState() == ImConnection.LOGGING_IN) { conn.suspend(); } } } public ImConnectionAdapter getConnection(String userAddress) { return mConnectionsByUser.get(userAddress); } private final IRemoteImService.Stub mBinder = new IRemoteImService.Stub() { @Override public List<ImPluginInfo> getAllPlugins() { return new ArrayList<ImPluginInfo>(mPluginHelper.getPluginsInfo()); } @Override public void addConnectionCreatedListener(IConnectionCreationListener listener) { if (listener != null) { mRemoteListeners.register(listener); } } @Override public void removeConnectionCreatedListener(IConnectionCreationListener listener) { if (listener != null) { mRemoteListeners.unregister(listener); } } @Override public IImConnection createConnection(long providerId, long accountId) { return RemoteImService.this.do_createConnection(providerId, accountId); } @Override public List getActiveConnections() { ArrayList<IBinder> result = new ArrayList<IBinder>(mConnections.size()); for (IImConnection conn : mConnections.values()) { result.add(conn.asBinder()); } return result; } @Override public IImConnection getConnection(long providerId) { return mConnections.get(providerId); } @Override public void dismissNotifications(long providerId) { mStatusBarNotifier.dismissNotifications(providerId); } @Override public void dismissChatNotification(long providerId, String username) { mStatusBarNotifier.dismissChatNotification(providerId, username); } @Override public boolean unlockOtrStore (String password) { // OtrAndroidKeyManagerImpl.setKeyStorePassword(password); return true; } @Override public IOtrKeyManager getOtrKeyManager() { OtrAndroidKeyManagerImpl keyMgr = OtrAndroidKeyManagerImpl.getInstance(RemoteImService.this); return keyMgr; } @Override public void setKillProcessOnStop (boolean killProcessOnStop) { mKillProcessOnStop = killProcessOnStop; } @Override public void enableDebugLogging (boolean debug) { Debug.DEBUG_ENABLED = debug; } @Override public void updateStateFromSettings() throws RemoteException { updateOtrPolicy (); } @Override public void shutdownAndLock () { shutdown(); } }; private boolean mKillProcessOnStop = false; /* //the concept of "background data is deprecated from Android // the only thing that matters is checking if Network is available and connected private final class SettingsMonitor extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED.equals(action)) { ConnectivityManager manager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); setBackgroundData(manager.getBackgroundDataSetting()); handleBackgroundDataSettingChange(); } } } */ private final class ServiceHandler extends Handler { public ServiceHandler() { } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SHOW_TOAST: Toast.makeText(RemoteImService.this, (CharSequence) msg.obj, Toast.LENGTH_SHORT).show(); break; default: } } } @Override public void sessionStatusChanged(SessionID sessionID) { //this method does nothing! // Log.d(TAG,"OTR session status changed: " + sessionID.getRemoteUserId()); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void onTaskRemoved(Intent rootIntent) { Debug.recordTrail(this, LAST_SWIPE_TRAIL_TAG, new Date()); Intent intent = new Intent(this, DummyActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= 11) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } @Override public void onCacheWordLocked() { //do nothing here? 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); } } else if (tempKey != null) { openEncryptedStores(tempKey, true); ((ImApp)getApplication()).initAccountInfo(); // Check and login accounts if network is ready, otherwise it's checked // when the network becomes available. if (mNeedCheckAutoLogin && mNetworkState != NetworkConnectivityReceiver.State.NOT_CONNECTED) { mNeedCheckAutoLogin = !autoLogin();; } } } private byte[] tempKey = null; @Override public void onCacheWordOpened() { // mCacheWord.setTimeout(0); tempKey = mCacheWord.getEncryptionKey(); openEncryptedStores(tempKey, true); ((ImApp)getApplication()).initAccountInfo(); // Check and login accounts if network is ready, otherwise it's checked // when the network becomes available. if (mNeedCheckAutoLogin && mNetworkState != NetworkConnectivityReceiver.State.NOT_CONNECTED) { mNeedCheckAutoLogin = !autoLogin();; } checkUpgrade(); } @Override public void onCacheWordUninitialized() { // TODO Auto-generated method stub } private boolean openEncryptedStores(byte[] key, boolean allowCreate) { SecureMediaStore.init(this, key); if (Imps.isUnlocked(this)) { return true; } else { return false; } } }