/*
* 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;
}
}
}