diff options
Diffstat (limited to 'src/com/android/settings')
4 files changed, 202 insertions, 18 deletions
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 1348d48..05a655a 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -66,6 +66,10 @@ public class SecuritySettings extends PreferenceActivity { private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback"; + // Encrypted File Systems constants + private static final String PROPERTY_EFS_ENABLED = "persist.security.efs.enabled"; + private static final String PROPERTY_EFS_TRANSITION = "persist.security.efs.trans"; + private CheckBoxPreference mVisiblePattern; private CheckBoxPreference mTactileFeedback; @@ -80,6 +84,9 @@ public class SecuritySettings extends PreferenceActivity { // Credential storage private CredentialStorage mCredentialStorage = new CredentialStorage(); + // Encrypted file system + private CheckBoxPreference mEncryptedFSEnabled; + private CheckBoxPreference mNetwork; private CheckBoxPreference mGps; private CheckBoxPreference mAssistedGps; @@ -209,6 +216,11 @@ public class SecuritySettings extends PreferenceActivity { root.addPreference(credentialsCat); mCredentialStorage.createPreferences(credentialsCat, CredentialStorage.TYPE_KEYSTORE); + // File System Encryption + PreferenceCategory encryptedfsCat = new PreferenceCategory(this); + encryptedfsCat.setTitle(R.string.encrypted_fs_category); + //root.addPreference(encryptedfsCat); + mCredentialStorage.createPreferences(encryptedfsCat, CredentialStorage.TYPE_ENCRYPTEDFS); return root; } @@ -302,18 +314,21 @@ public class SecuritySettings extends PreferenceActivity { private static final int MINIMUM_PASSWORD_LENGTH = 8; private static final int TYPE_KEYSTORE = 0; + private static final int TYPE_ENCRYPTEDFS = 1; // Dialog identifiers private static final int DLG_BASE = 0; private static final int DLG_UNLOCK = DLG_BASE + 1; private static final int DLG_PASSWORD = DLG_UNLOCK + 1; private static final int DLG_RESET = DLG_PASSWORD + 1; + private static final int DLG_ENABLE_EFS = DLG_RESET + 1; private KeyStore mKeyStore = KeyStore.getInstance(); private int mState; private boolean mSubmit = false; private boolean mExternal = false; + private boolean mWillEnableEncryptedFS; private int mShowingDialog = 0; // Key Store controls @@ -322,6 +337,10 @@ public class SecuritySettings extends PreferenceActivity { private Preference mPasswordButton; private Preference mResetButton; + + // Encrypted file system controls + private CheckBoxPreference mEncryptedFSEnabled; + void resume() { mState = mKeyStore.test(); updatePreferences(mState); @@ -373,6 +392,10 @@ public class SecuritySettings extends PreferenceActivity { lock(); } return true; + } else if (preference == mEncryptedFSEnabled) { + Boolean bval = (Boolean)value; + mWillEnableEncryptedFS = bval.booleanValue(); + showSwitchEncryptedFSDialog(); } return true; } @@ -391,9 +414,26 @@ public class SecuritySettings extends PreferenceActivity { } public void onClick(DialogInterface dialog, int button) { - mSubmit = (button == DialogInterface.BUTTON_POSITIVE); - if (button == DialogInterface.BUTTON_NEUTRAL) { - reset(); + if (mShowingDialog != DLG_ENABLE_EFS) { + mSubmit = (button == DialogInterface.BUTTON_POSITIVE); + if (button == DialogInterface.BUTTON_NEUTRAL) { + reset(); + } + } else { + if (button == DialogInterface.BUTTON_POSITIVE) { + Intent intent = new Intent("android.intent.action.MASTER_CLEAR"); + intent.putExtra("enableEFS", mWillEnableEncryptedFS); + sendBroadcast(intent); + updatePreferences(mState); + } else if (button == DialogInterface.BUTTON_NEGATIVE) { + // Cancel action + Toast.makeText(SecuritySettings.this, R.string.encrypted_fs_cancel_confirm, + Toast.LENGTH_SHORT).show(); + updatePreferences(mState); + } else { + // Unknown - should not happen + return; + } } } @@ -507,16 +547,25 @@ public class SecuritySettings extends PreferenceActivity { category.addPreference(mResetButton); break; + case TYPE_ENCRYPTEDFS: + mEncryptedFSEnabled = new CheckBoxPreference(SecuritySettings.this); + mEncryptedFSEnabled.setTitle(R.string.encrypted_fs_enable); + mEncryptedFSEnabled.setSummary(R.string.encrypted_fs_enable_summary); + mEncryptedFSEnabled.setOnPreferenceChangeListener(this); + // category.addPreference(mEncryptedFSEnabled); + break; } } private void updatePreferences(int state) { mAccessCheckBox.setChecked(state == KeyStore.NO_ERROR); - - mResetButton.setEnabled(state != KeyStore.UNINITIALIZED); - mAccessCheckBox.setEnabled(state != KeyStore.UNINITIALIZED); + boolean encFSEnabled = SystemProperties.getBoolean(PROPERTY_EFS_ENABLED, + false); + mResetButton.setEnabled((!encFSEnabled) && (state != KeyStore.UNINITIALIZED)); + mAccessCheckBox.setEnabled((state != KeyStore.UNINITIALIZED) && (!encFSEnabled)); // Encrypted File system preferences + mEncryptedFSEnabled.setChecked(encFSEnabled); // Show a toast message if the state is changed. if (mState == state) { @@ -586,5 +635,24 @@ public class SecuritySettings extends PreferenceActivity { .setNegativeButton(getString(android.R.string.cancel), this) .create().show(); } + + private void showSwitchEncryptedFSDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(SecuritySettings.this) + .setCancelable(false) + .setTitle(R.string.encrypted_fs_alert_dialog_title); + + mShowingDialog = DLG_ENABLE_EFS; + if (mWillEnableEncryptedFS) { + builder.setMessage(R.string.encrypted_fs_enable_dialog) + .setPositiveButton(R.string.encrypted_fs_enable_button, this) + .setNegativeButton(R.string.encrypted_fs_cancel_button, this) + .create().show(); + } else { + builder.setMessage(R.string.encrypted_fs_disable_dialog) + .setPositiveButton(R.string.encrypted_fs_disable_button, this) + .setNegativeButton(R.string.encrypted_fs_cancel_button, this) + .create().show(); + } + } } } diff --git a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java index 08534f3..2a8af5f 100644 --- a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java +++ b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java @@ -179,6 +179,9 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity } private void onProfileCheckedStateChanged(Profile profile, boolean checked) { + LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager + .getProfileManager(mManager, profile); + profileManager.setPreferred(mCachedDevice.getDevice(), checked); if (mOnlineMode) { if (checked) { mCachedDevice.connect(profile); @@ -186,10 +189,6 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity mCachedDevice.disconnect(profile); } } - - LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager - .getProfileManager(mManager, profile); - profileManager.setPreferred(mCachedDevice.getDevice(), checked); } public void onDeviceAttributesChanged(CachedBluetoothDevice cachedDevice) { diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java index f318987..d0f8099 100644 --- a/src/com/android/settings/bluetooth/DockService.java +++ b/src/com/android/settings/bluetooth/DockService.java @@ -18,6 +18,7 @@ package com.android.settings.bluetooth; import com.android.settings.R; import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; +import com.android.settings.bluetooth.LocalBluetoothProfileManager.ServiceListener; import android.app.AlertDialog; import android.app.Notification; @@ -48,7 +49,7 @@ import java.util.Set; public class DockService extends Service implements AlertDialog.OnMultiChoiceClickListener, DialogInterface.OnClickListener, DialogInterface.OnDismissListener, - CompoundButton.OnCheckedChangeListener { + CompoundButton.OnCheckedChangeListener, ServiceListener { private static final String TAG = "DockService"; @@ -101,6 +102,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli // Created in OnCreate() private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; + private Runnable mRunnable; private DockService mContext; private LocalBluetoothManager mBtManager; @@ -138,6 +140,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli @Override public void onDestroy() { if (DEBUG) Log.d(TAG, "onDestroy"); + mRunnable = null; + LocalBluetoothProfileManager.removeServiceListener(this); if (mDialog != null) { mDialog.dismiss(); mDialog = null; @@ -228,8 +232,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli // This method gets messages from both onStartCommand and mServiceHandler/mServiceLooper private synchronized void processMessage(Message msg) { int msgType = msg.what; - int state = msg.arg1; - int startId = msg.arg2; + final int state = msg.arg1; + final int startId = msg.arg2; boolean deferFinishCall = false; BluetoothDevice device = null; if (msg.obj != null) { @@ -271,12 +275,23 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli } mDevice = device; - if (mBtManager.getDockAutoConnectSetting(device.getAddress())) { - // Setting == auto connect - initBtSettings(mContext, device, state, false); - applyBtSettings(mDevice, startId); + + // Register first in case LocalBluetoothProfileManager + // becomes ready after isManagerReady is called and it + // would be too late to register a service listener. + LocalBluetoothProfileManager.addServiceListener(this); + if (LocalBluetoothProfileManager.isManagerReady()) { + handleDocked(device, state, startId); + // Not needed after all + LocalBluetoothProfileManager.removeServiceListener(this); } else { - createDialog(mContext, mDevice, state, startId); + final BluetoothDevice d = device; + mRunnable = new Runnable() { + public void run() { + handleDocked(d, state, startId); + } + }; + deferFinishCall = true; } } break; @@ -721,8 +736,21 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli } } + private synchronized void handleDocked(final BluetoothDevice device, final int state, + final int startId) { + if (mBtManager.getDockAutoConnectSetting(device.getAddress())) { + // Setting == auto connect + initBtSettings(mContext, device, state, false); + applyBtSettings(mDevice, startId); + } else { + createDialog(mContext, device, state, startId); + } + } + private synchronized void handleUndocked(Context context, LocalBluetoothManager localManager, BluetoothDevice device) { + mRunnable = null; + LocalBluetoothProfileManager.removeServiceListener(this); if (mDialog != null) { mDialog.dismiss(); mDialog = null; @@ -778,4 +806,15 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli editor.commit(); return; } + + public synchronized void onServiceConnected() { + if (mRunnable != null) { + mRunnable.run(); + mRunnable = null; + LocalBluetoothProfileManager.removeServiceListener(this); + } + } + + public void onServiceDisconnected() { + } } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java index f3aaade..6179dc7 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java @@ -28,6 +28,8 @@ import android.util.Log; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +55,29 @@ public abstract class LocalBluetoothProfileManager { BluetoothUuid.ObexObjectPush }; + /** + * An interface for notifying BluetoothHeadset IPC clients when they have + * been connected to the BluetoothHeadset service. + */ + public interface ServiceListener { + /** + * Called to notify the client when this proxy object has been + * connected to the BluetoothHeadset service. Clients must wait for + * this callback before making IPC calls on the BluetoothHeadset + * service. + */ + public void onServiceConnected(); + + /** + * Called to notify the client that this proxy object has been + * disconnected from the BluetoothHeadset service. Clients must not + * make IPC calls on the BluetoothHeadset service after this callback. + * This callback will currently only occur if the application hosting + * the BluetoothHeadset service, but may be called more often in future. + */ + public void onServiceDisconnected(); + } + // TODO: close profiles when we're shutting down private static Map<Profile, LocalBluetoothProfileManager> sProfileMap = new HashMap<Profile, LocalBluetoothProfileManager>(); @@ -76,6 +101,26 @@ public abstract class LocalBluetoothProfileManager { } } + private static LinkedList<ServiceListener> mServiceListeners = new LinkedList<ServiceListener>(); + + public static void addServiceListener(ServiceListener l) { + mServiceListeners.add(l); + } + + public static void removeServiceListener(ServiceListener l) { + mServiceListeners.remove(l); + } + + public static boolean isManagerReady() { + // Getting just the headset profile is fine for now. Will need to deal with A2DP + // and others if they aren't always in a ready state. + LocalBluetoothProfileManager profileManager = sProfileMap.get(Profile.HEADSET); + if (profileManager == null) { + return sProfileMap.size() > 0; + } + return profileManager.isProfileReady(); + } + public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager, Profile profile) { // Note: This code assumes that "localManager" is same as the @@ -144,6 +189,8 @@ public abstract class LocalBluetoothProfileManager { return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device)); } + public abstract boolean isProfileReady(); + // TODO: int instead of enum public enum Profile { HEADSET(R.string.bluetooth_profile_headset), @@ -247,6 +294,11 @@ public abstract class LocalBluetoothProfileManager { return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; } } + + @Override + public boolean isProfileReady() { + return true; + } } /** @@ -256,6 +308,7 @@ public abstract class LocalBluetoothProfileManager { implements BluetoothHeadset.ServiceListener { private BluetoothHeadset mService; private Handler mUiHandler = new Handler(); + private boolean profileReady = false; public HeadsetProfileManager(LocalBluetoothManager localManager) { super(localManager); @@ -263,6 +316,7 @@ public abstract class LocalBluetoothProfileManager { } public void onServiceConnected() { + profileReady = true; // This could be called on a non-UI thread, funnel to UI thread. mUiHandler.post(new Runnable() { public void run() { @@ -277,9 +331,28 @@ public abstract class LocalBluetoothProfileManager { BluetoothHeadset.STATE_CONNECTED); } }); + + if (mServiceListeners.size() > 0) { + Iterator<ServiceListener> it = mServiceListeners.iterator(); + while(it.hasNext()) { + it.next().onServiceConnected(); + } + } } public void onServiceDisconnected() { + profileReady = false; + if (mServiceListeners.size() > 0) { + Iterator<ServiceListener> it = mServiceListeners.iterator(); + while(it.hasNext()) { + it.next().onServiceDisconnected(); + } + } + } + + @Override + public boolean isProfileReady() { + return profileReady; } @Override @@ -424,6 +497,11 @@ public abstract class LocalBluetoothProfileManager { } @Override + public boolean isProfileReady() { + return true; + } + + @Override public int convertState(int oppState) { switch (oppState) { case 0: |