diff options
Diffstat (limited to 'src')
107 files changed, 2007 insertions, 8119 deletions
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java index 5b8ad0d..06648db 100644 --- a/src/com/android/settings/AirplaneModeEnabler.java +++ b/src/com/android/settings/AirplaneModeEnabler.java @@ -29,6 +29,7 @@ import android.provider.Settings; import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyProperties; +import com.android.settingslib.WirelessUtils; public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener { @@ -71,7 +72,7 @@ public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListene public void resume() { - mSwitchPref.setChecked(isAirplaneModeOn(mContext)); + mSwitchPref.setChecked(WirelessUtils.isAirplaneModeOn(mContext)); mPhoneStateReceiver.registerIntent(); mSwitchPref.setOnPreferenceChangeListener(this); @@ -86,11 +87,6 @@ public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListene mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver); } - public static boolean isAirplaneModeOn(Context context) { - return Settings.Global.getInt(context.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) != 0; - } - private void setAirplaneModeOn(boolean enabling) { // Change the system setting Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, @@ -113,7 +109,7 @@ public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListene * - mobile does not send failure notification, fail on timeout. */ private void onAirplaneModeChanged() { - mSwitchPref.setChecked(isAirplaneModeOn(mContext)); + mSwitchPref.setChecked(WirelessUtils.isAirplaneModeOn(mContext)); } /** diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index b289e7a..bfb328d 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -76,17 +76,15 @@ public class ChooseLockGeneric extends SettingsActivity { private static final String KEY_UNLOCK_BACKUP_INFO = "unlock_backup_info"; private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off"; private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none"; - private static final String KEY_UNLOCK_SET_BIOMETRIC_WEAK = "unlock_set_biometric_weak"; private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin"; private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password"; private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern"; private static final int CONFIRM_EXISTING_REQUEST = 100; - private static final int FALLBACK_REQUEST = 101; private static final int ENABLE_ENCRYPTION_REQUEST = 102; + private static final int CHOOSE_LOCK_REQUEST = 103; private static final String PASSWORD_CONFIRMED = "password_confirmed"; private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; - private static final String FINISH_PENDING = "finish_pending"; private static final String TAG = "ChooseLockGenericFragment"; public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality"; @@ -100,7 +98,6 @@ public class ChooseLockGeneric extends SettingsActivity { private KeyStore mKeyStore; private boolean mPasswordConfirmed = false; private boolean mWaitingForConfirmation = false; - private boolean mFinishPending = false; private int mEncryptionRequestQuality; private boolean mEncryptionRequestDisabled; private boolean mRequirePassword; @@ -125,7 +122,6 @@ public class ChooseLockGeneric extends SettingsActivity { if (savedInstanceState != null) { mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION); - mFinishPending = savedInstanceState.getBoolean(FINISH_PENDING); mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY); mEncryptionRequestDisabled = savedInstanceState.getBoolean( ENCRYPT_REQUESTED_DISABLED); @@ -146,15 +142,6 @@ public class ChooseLockGeneric extends SettingsActivity { } @Override - public void onResume() { - super.onResume(); - if (mFinishPending) { - mFinishPending = false; - finish(); - } - } - - @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { final String key = preference.getKey(); @@ -195,36 +182,20 @@ public class ChooseLockGeneric extends SettingsActivity { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v = super.onCreateView(inflater, container, savedInstanceState); - final boolean onlyShowFallback = getActivity().getIntent() - .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false); - if (onlyShowFallback) { - View header = v.inflate(getActivity(), - R.layout.weak_biometric_fallback_header, null); - ((ListView) v.findViewById(android.R.id.list)).addHeaderView(header, null, false); - } - - return v; - } - - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mWaitingForConfirmation = false; if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) { mPasswordConfirmed = true; updatePreferencesOrFinish(); - } else if (requestCode == FALLBACK_REQUEST) { - mChooseLockSettingsHelper.utils().deleteTempGallery(); - getActivity().setResult(resultCode); - finish(); } else if (requestCode == ENABLE_ENCRYPTION_REQUEST && resultCode == Activity.RESULT_OK) { mRequirePassword = data.getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); updateUnlockMethodAndFinish(mEncryptionRequestQuality, mEncryptionRequestDisabled); + } else if (requestCode == CHOOSE_LOCK_REQUEST) { + getActivity().setResult(resultCode, data); + finish(); } else { getActivity().setResult(Activity.RESULT_CANCELED); finish(); @@ -237,7 +208,6 @@ public class ChooseLockGeneric extends SettingsActivity { // Saved so we don't force user to re-enter their password if configuration changes outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed); outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation); - outState.putBoolean(FINISH_PENDING, mFinishPending); outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality); outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled); } @@ -248,22 +218,21 @@ public class ChooseLockGeneric extends SettingsActivity { if (quality == -1) { // If caller didn't specify password quality, show UI and allow the user to choose. quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1); - MutableBoolean allowBiometric = new MutableBoolean(false); - quality = upgradeQuality(quality, allowBiometric); + quality = upgradeQuality(quality); final PreferenceScreen prefScreen = getPreferenceScreen(); if (prefScreen != null) { prefScreen.removeAll(); } addPreferencesFromResource(R.xml.security_settings_picker); - disableUnusablePreferences(quality, allowBiometric); + disableUnusablePreferences(quality); updatePreferenceSummaryIfNeeded(); } else { updateUnlockMethodAndFinish(quality, false); } } - /** increases the quality if necessary, and returns whether biometric is allowed */ - private int upgradeQuality(int quality, MutableBoolean allowBiometric) { + /** increases the quality if necessary */ + private int upgradeQuality(int quality) { quality = upgradeQualityForDPM(quality); quality = upgradeQualityForKeyStore(quality); return quality; @@ -292,28 +261,21 @@ public class ChooseLockGeneric extends SettingsActivity { * implementation is in disableUnusablePreferenceImpl. * * @param quality the requested quality. - * @param allowBiometric whether to allow biometic screen lock. */ - protected void disableUnusablePreferences(final int quality, - MutableBoolean allowBiometric) { - disableUnusablePreferencesImpl(quality, allowBiometric, false /* hideDisabled */); + protected void disableUnusablePreferences(final int quality) { + disableUnusablePreferencesImpl(quality, false /* hideDisabled */); } /*** * Disables preferences that are less secure than required quality. * * @param quality the requested quality. - * @param allowBiometric whether to allow biometic screen lock. * @param hideDisabled whether to hide disable screen lock options. */ protected void disableUnusablePreferencesImpl(final int quality, - MutableBoolean allowBiometric, boolean hideDisabled) { + boolean hideDisabled) { final PreferenceScreen entries = getPreferenceScreen(); final Intent intent = getActivity().getIntent(); - final boolean onlyShowFallback = intent.getBooleanExtra( - LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false); - final boolean weakBiometricAvailable = - mChooseLockSettingsHelper.utils().isBiometricWeakInstalled(); // if there are multiple users, disable "None" setting UserManager mUm = (UserManager) getSystemService(Context.USER_SERVICE); @@ -331,10 +293,6 @@ public class ChooseLockGeneric extends SettingsActivity { visible = singleUser; // don't show when there's more than 1 user } else if (KEY_UNLOCK_SET_NONE.equals(key)) { enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - } else if (KEY_UNLOCK_SET_BIOMETRIC_WEAK.equals(key)) { - enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK || - allowBiometric.value; - visible = weakBiometricAvailable; // If not available, then don't show it. } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) { enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; } else if (KEY_UNLOCK_SET_PIN.equals(key)) { @@ -345,7 +303,7 @@ public class ChooseLockGeneric extends SettingsActivity { if (hideDisabled) { visible = visible && enabled; } - if (!visible || (onlyShowFallback && !allowedForFallback(key))) { + if (!visible) { entries.removePreference(pref); } else if (!enabled) { pref.setSummary(R.string.unlock_set_unlock_disabled_summary); @@ -381,46 +339,16 @@ public class ChooseLockGeneric extends SettingsActivity { } } - /** - * Check whether the key is allowed for fallback (e.g. bio sensor). Returns true if it's - * supported as a backup. - * - * @param key - * @return true if allowed - */ - private boolean allowedForFallback(String key) { - return KEY_UNLOCK_BACKUP_INFO.equals(key) || - KEY_UNLOCK_SET_PATTERN.equals(key) || KEY_UNLOCK_SET_PIN.equals(key); - } - - private Intent getBiometricSensorIntent() { - Intent fallBackIntent = new Intent().setClass(getActivity(), - ChooseLockGeneric.InternalActivity.class); - fallBackIntent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, true); - fallBackIntent.putExtra(CONFIRM_CREDENTIALS, false); - fallBackIntent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, - R.string.backup_lock_settings_picker_title); - - boolean showTutorial = ALWAY_SHOW_TUTORIAL || - !mChooseLockSettingsHelper.utils().isBiometricWeakEverChosen(); - Intent intent = new Intent(); - intent.setClassName("com.android.facelock", "com.android.facelock.SetupIntro"); - intent.putExtra("showTutorial", showTutorial); - PendingIntent pending = PendingIntent.getActivity(getActivity(), 0, fallBackIntent, 0); - intent.putExtra("PendingIntent", pending); - return intent; - } - protected Intent getLockPasswordIntent(Context context, int quality, - final boolean isFallback, int minLength, final int maxLength, + int minLength, final int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials) { - return ChooseLockPassword.createIntent(context, quality, isFallback, minLength, + return ChooseLockPassword.createIntent(context, quality, minLength, maxLength, requirePasswordToDecrypt, confirmCredentials); } - protected Intent getLockPatternIntent(Context context, final boolean isFallback, - final boolean requirePassword, final boolean confirmCredentials) { - return ChooseLockPattern.createIntent(context, isFallback, requirePassword, + protected Intent getLockPatternIntent(Context context, final boolean requirePassword, + final boolean confirmCredentials) { + return ChooseLockPattern.createIntent(context, requirePassword, confirmCredentials); } @@ -444,10 +372,7 @@ public class ChooseLockGeneric extends SettingsActivity { throw new IllegalStateException("Tried to update password without confirming it"); } - final boolean isFallback = getActivity().getIntent() - .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false); - - quality = upgradeQuality(quality, null); + quality = upgradeQuality(quality); final Context context = getActivity(); if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { @@ -456,33 +381,15 @@ public class ChooseLockGeneric extends SettingsActivity { minLength = MIN_PASSWORD_LENGTH; } final int maxLength = mDPM.getPasswordMaximumLength(quality); - Intent intent = getLockPasswordIntent(context, quality, isFallback, minLength, + Intent intent = getLockPasswordIntent(context, quality, minLength, maxLength, mRequirePassword, /* confirm credentials */false); - if (isFallback) { - startActivityForResult(intent, FALLBACK_REQUEST); - return; - } else { - mFinishPending = true; - intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); - startActivity(intent); - } + startActivityForResult(intent, CHOOSE_LOCK_REQUEST); } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { - Intent intent = getLockPatternIntent(context, isFallback, mRequirePassword, + Intent intent = getLockPatternIntent(context, mRequirePassword, /* confirm credentials */false); - if (isFallback) { - startActivityForResult(intent, FALLBACK_REQUEST); - return; - } else { - mFinishPending = true; - intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); - startActivity(intent); - } - } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) { - Intent intent = getBiometricSensorIntent(); - mFinishPending = true; - startActivity(intent); + startActivityForResult(intent, CHOOSE_LOCK_REQUEST); } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { - mChooseLockSettingsHelper.utils().clearLock(false); + mChooseLockSettingsHelper.utils().clearLock(); mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled); getActivity().setResult(Activity.RESULT_OK); finish(); @@ -526,9 +433,6 @@ public class ChooseLockGeneric extends SettingsActivity { } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) { updateUnlockMethodAndFinish( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ ); - } else if (KEY_UNLOCK_SET_BIOMETRIC_WEAK.equals(unlockMethod)) { - maybeEnableEncryption( - DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, false); } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) { maybeEnableEncryption( DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false); diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java index fa1c678..b85daa7 100644 --- a/src/com/android/settings/ChooseLockPassword.java +++ b/src/com/android/settings/ChooseLockPassword.java @@ -63,7 +63,7 @@ public class ChooseLockPassword extends SettingsActivity { return modIntent; } - public static Intent createIntent(Context context, int quality, final boolean isFallback, + public static Intent createIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials) { Intent intent = new Intent().setClass(context, ChooseLockPassword.class); @@ -71,7 +71,6 @@ public class ChooseLockPassword extends SettingsActivity { intent.putExtra(PASSWORD_MIN_KEY, minLength); intent.putExtra(PASSWORD_MAX_KEY, maxLength); intent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, confirmCredentials); - intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, isFallback); intent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, requirePasswordToDecrypt); return intent; } @@ -102,7 +101,7 @@ public class ChooseLockPassword extends SettingsActivity { private static final String KEY_FIRST_PIN = "first_pin"; private static final String KEY_UI_STAGE = "ui_stage"; private TextView mPasswordEntry; - private int mPasswordMinLength = 4; + private int mPasswordMinLength = LockPatternUtils.MIN_LOCK_PASSWORD_SIZE; private int mPasswordMaxLength = 16; private int mPasswordMinLetters = 0; private int mPasswordMinUpperCase = 0; @@ -179,9 +178,10 @@ public class ChooseLockPassword extends SettingsActivity { } mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality), mLockPatternUtils.getRequestedPasswordQuality()); - mPasswordMinLength = Math.max( - intent.getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength), mLockPatternUtils - .getRequestedMinimumPasswordLength()); + mPasswordMinLength = Math.max(Math.max( + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE, + intent.getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength)), + mLockPatternUtils.getRequestedMinimumPasswordLength()); mPasswordMaxLength = intent.getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength); mPasswordMinLetters = Math.max(intent.getIntExtra(PASSWORD_MIN_LETTERS_KEY, mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters()); @@ -431,14 +431,12 @@ public class ChooseLockPassword extends SettingsActivity { } } else if (mUiStage == Stage.NeedToConfirm) { if (mFirstPin.equals(pin)) { - final boolean isFallback = getActivity().getIntent().getBooleanExtra( - LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false); boolean wasSecureBefore = mLockPatternUtils.isSecure(); - mLockPatternUtils.clearLock(isFallback); + mLockPatternUtils.clearLock(); final boolean required = getActivity().getIntent().getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); mLockPatternUtils.setCredentialRequiredToDecrypt(required); - mLockPatternUtils.saveLockPassword(pin, mRequestedQuality, isFallback); + mLockPatternUtils.saveLockPassword(pin, mRequestedQuality); getActivity().setResult(RESULT_FINISHED); getActivity().finish(); mDone = true; diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java index 38f908e..b64f102 100644 --- a/src/com/android/settings/ChooseLockPattern.java +++ b/src/com/android/settings/ChooseLockPattern.java @@ -69,12 +69,11 @@ public class ChooseLockPattern extends SettingsActivity { return modIntent; } - public static Intent createIntent(Context context, final boolean isFallback, + public static Intent createIntent(Context context, boolean requirePassword, boolean confirmCredentials) { Intent intent = new Intent(context, ChooseLockPattern.class); intent.putExtra("key_lock_method", "pattern"); intent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, confirmCredentials); - intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, isFallback); intent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, requirePassword); return intent; } @@ -563,16 +562,12 @@ public class ChooseLockPattern extends SettingsActivity { LockPatternUtils utils = mChooseLockSettingsHelper.utils(); final boolean lockVirgin = !utils.isPatternEverChosen(); - final boolean isFallback = getActivity().getIntent() - .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false); - boolean wasSecureBefore = utils.isSecure(); final boolean required = getActivity().getIntent().getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); utils.setCredentialRequiredToDecrypt(required); - utils.setLockPatternEnabled(true); - utils.saveLockPattern(mChosenPattern, isFallback); + utils.saveLockPattern(mChosenPattern); if (lockVirgin) { utils.setVisiblePatternEnabled(true); diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java index 3086a7a..bba45ce 100644 --- a/src/com/android/settings/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/ChooseLockSettingsHelper.java @@ -95,7 +95,7 @@ public final class ChooseLockSettingsHelper { */ private boolean confirmPattern(int request, CharSequence message, CharSequence details, boolean returnCredentials) { - if (!mLockPatternUtils.isLockPatternEnabled() || !mLockPatternUtils.savedPatternExists()) { + if (!mLockPatternUtils.isLockPatternEnabled()) { return false; } final Intent intent = new Intent(); diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java index caf691d..87d401c 100644 --- a/src/com/android/settings/ConfirmLockPattern.java +++ b/src/com/android/settings/ConfirmLockPattern.java @@ -148,7 +148,7 @@ public class ConfirmLockPattern extends SettingsActivity { // on first launch, if no lock pattern is set, then finish with // success (don't want user to get stuck confirming something that // doesn't exist). - if (!mLockPatternUtils.savedPatternExists()) { + if (!mLockPatternUtils.isLockPatternEnabled()) { getActivity().setResult(Activity.RESULT_OK); getActivity().finish(); } diff --git a/src/com/android/settings/CreateShortcut.java b/src/com/android/settings/CreateShortcut.java index 0bf265f..fa2ce7c 100644 --- a/src/com/android/settings/CreateShortcut.java +++ b/src/com/android/settings/CreateShortcut.java @@ -23,6 +23,7 @@ import android.view.View; import android.widget.ListView; import com.android.settings.Settings.TetherSettingsActivity; +import com.android.settingslib.TetherUtil; import java.util.List; @@ -64,7 +65,7 @@ public class CreateShortcut extends LauncherActivity { for (int i = activities.size() - 1; i >= 0; i--) { ResolveInfo info = activities.get(i); if (info.activityInfo.name.endsWith(TetherSettingsActivity.class.getSimpleName())) { - if (!TetherSettings.showInShortcuts(this)) { + if (!TetherUtil.isTetheringSupported(this)) { activities.remove(i); } } diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java index f08ed5a..7005ece 100644 --- a/src/com/android/settings/CryptKeeper.java +++ b/src/com/android/settings/CryptKeeper.java @@ -48,10 +48,10 @@ import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; import android.view.View.OnTouchListener; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -66,10 +66,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; -import static com.android.internal.widget.LockPatternView.DisplayMode; - import java.util.List; +import static com.android.internal.widget.LockPatternView.DisplayMode; + /** * Settings screens to show the UI flows for encrypting/decrypting the device. * @@ -408,11 +408,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList // If we are not encrypted or encrypting, get out quickly. final String state = SystemProperties.get("vold.decrypt"); if (!isDebugView() && ("".equals(state) || DECRYPT_STATE.equals(state))) { - // Disable the crypt keeper. - PackageManager pm = getPackageManager(); - ComponentName name = new ComponentName(this, CryptKeeper.class); - pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); + disableCryptKeeperComponent(this); // Typically CryptKeeper is launched as the home app. We didn't // want to be running, so need to finish this activity. We can count // on the activity manager re-launching the new home app upon finishing @@ -1021,4 +1017,12 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList public void afterTextChanged(Editable s) { return; } + + private static void disableCryptKeeperComponent(Context context) { + PackageManager pm = context.getPackageManager(); + ComponentName name = new ComponentName(context, CryptKeeper.class); + Log.d(TAG, "Disabling component " + name); + pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } } diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index c4c79d1..cba0879 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -1837,8 +1837,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final AppItem item = mItems.get(position); if (getItemViewType(position) == 1) { if (convertView == null) { - convertView = inflateCategoryHeader(LayoutInflater.from(parent.getContext()), - parent); + convertView = Utils.inflateCategoryHeader(LayoutInflater.from( + parent.getContext()), parent); } final TextView title = (TextView) convertView.findViewById(android.R.id.title); @@ -2529,14 +2529,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable return view; } - private static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup root) { - final TypedArray a = inflater.getContext().obtainStyledAttributes(null, - com.android.internal.R.styleable.Preference, - com.android.internal.R.attr.preferenceCategoryStyle, 0); - final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, 0); - return inflater.inflate(resId, root, false); - } - /** * Test if any networks are currently limited. */ diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java index a001fd7..dd7f5df 100644 --- a/src/com/android/settings/DevelopmentSettings.java +++ b/src/com/android/settings/DevelopmentSettings.java @@ -23,16 +23,19 @@ import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.app.backup.IBackupManager; import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.hardware.usb.IUsbManager; +import android.hardware.usb.UsbManager; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.BatteryManager; @@ -58,7 +61,9 @@ import android.text.TextUtils; import android.util.Log; import android.view.HardwareRenderer; import android.view.IWindowManager; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.Switch; import android.widget.TextView; @@ -142,6 +147,8 @@ public class DevelopmentSettings extends SettingsPreferenceFragment private static final String SELECT_LOGD_SIZE_KEY = "select_logd_size"; private static final String SELECT_LOGD_SIZE_PROPERTY = "persist.logd.size"; private static final String SELECT_LOGD_DEFAULT_SIZE_PROPERTY = "ro.logd.size"; + private static final String USB_CONFIGURATION_KEY = "select_usb_configuration"; + private static final String SELECT_USB_CONFIGURATION_PROPERTY = "sys.usb.config"; private static final String OPENGL_TRACES_KEY = "enable_opengl_traces"; @@ -213,6 +220,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment private SwitchPreference mForceRtlLayout; private ListPreference mDebugHwOverdraw; private ListPreference mLogdSize; + private ListPreference mUsbConfiguration; private ListPreference mTrackFrameTime; private ListPreference mShowNonRectClip; private ListPreference mWindowAnimationScale; @@ -337,6 +345,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment mWifiAggressiveHandover = findAndInitSwitchPref(WIFI_AGGRESSIVE_HANDOVER_KEY); mWifiAllowScansWithTraffic = findAndInitSwitchPref(WIFI_ALLOW_SCAN_WITH_TRAFFIC_KEY); mLogdSize = addListPreference(SELECT_LOGD_SIZE_KEY); + mUsbConfiguration = addListPreference(USB_CONFIGURATION_KEY); mWindowAnimationScale = addListPreference(WINDOW_ANIMATION_SCALE_KEY); mTransitionAnimationScale = addListPreference(TRANSITION_ANIMATION_SCALE_KEY); @@ -474,6 +483,15 @@ public class DevelopmentSettings extends SettingsPreferenceFragment } @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + IntentFilter filter = new IntentFilter(); + filter.addAction(UsbManager.ACTION_USB_STATE); + getActivity().registerReceiver(mUsbReceiver, filter); + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override public void onDestroyView() { super.onDestroyView(); @@ -482,6 +500,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment } mSwitchBar.removeOnSwitchChangeListener(this); mSwitchBar.hide(); + getActivity().unregisterReceiver(mUsbReceiver); } void updateSwitchPreference(SwitchPreference switchPreference, boolean value) { @@ -1122,6 +1141,42 @@ public class DevelopmentSettings extends SettingsPreferenceFragment updateLogdSizeValues(); } + private void updateUsbConfigurationValues() { + if (mUsbConfiguration != null) { + String currentValue = SystemProperties.get(SELECT_USB_CONFIGURATION_PROPERTY); + + // Ignore adb interface. The USB Manager adds or removes adb automatically + // depending on if USB debugging is enabled. + int adbIndex = currentValue.indexOf(",adb"); + if (adbIndex > 0) { + currentValue = currentValue.substring(0, adbIndex); + } + + String[] values = getResources().getStringArray(R.array.usb_configuration_values); + String[] titles = getResources().getStringArray(R.array.usb_configuration_titles); + int index = 1; // punt to second entry if not found + for (int i = 0; i < titles.length; i++) { + if (currentValue.equals(values[i])) { + index = i; + break; + } + } + if (index >= 0) { + mUsbConfiguration.setValue(values[index]); + mUsbConfiguration.setSummary(titles[index]); + } else { + mUsbConfiguration.setValue(""); + mUsbConfiguration.setSummary(""); + } + mUsbConfiguration.setOnPreferenceChangeListener(this); + } + } + + private void writeUsbConfigurationOption(Object newValue) { + UsbManager manager = (UsbManager)getActivity().getSystemService(Context.USB_SERVICE); + manager.setCurrentFunction(newValue.toString(), false); + } + private void updateCpuUsageOptions() { updateSwitchPreference(mShowCpuUsage, Settings.Global.getInt(getActivity().getContentResolver(), Settings.Global.SHOW_PROCESSES, 0) != 0); @@ -1478,6 +1533,9 @@ public class DevelopmentSettings extends SettingsPreferenceFragment } else if (preference == mLogdSize) { writeLogdSizeOption(newValue); return true; + } else if (preference == mUsbConfiguration) { + writeUsbConfigurationOption(newValue); + return true; } else if (preference == mWindowAnimationScale) { writeAnimationScaleOption(0, mWindowAnimationScale, newValue); return true; @@ -1592,6 +1650,13 @@ public class DevelopmentSettings extends SettingsPreferenceFragment } } + private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateUsbConfigurationValues(); + } + }; + static class SystemPropPoker extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java index c9f876b..83b222b 100644 --- a/src/com/android/settings/DeviceAdminAdd.java +++ b/src/com/android/settings/DeviceAdminAdd.java @@ -88,13 +88,11 @@ public class DeviceAdminAdd extends Activity { Button mActionButton; Button mCancelButton; - final ArrayList<View> mAddingPolicies = new ArrayList<View>(); - final ArrayList<View> mActivePolicies = new ArrayList<View>(); - boolean mAdding; boolean mRefreshing; boolean mWaitingForRemoveMsg; boolean mAddingProfileOwner; + boolean mAdminPoliciesInitialized; int mCurSysAppOpMode; int mCurToastAppOpMode; @@ -386,8 +384,7 @@ public class DeviceAdminAdd extends Activity { switch (id) { case DIALOG_WARNING: { CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING); - AlertDialog.Builder builder = new AlertDialog.Builder( - DeviceAdminAdd.this); + AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(msg); builder.setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { @@ -409,13 +406,6 @@ public class DeviceAdminAdd extends Activity { } } - static void setViewVisibility(ArrayList<View> views, int visibility) { - final int N = views.size(); - for (int i=0; i<N; i++) { - views.get(i).setVisibility(visibility); - } - } - void updateInterface() { mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager())); mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager())); @@ -438,36 +428,14 @@ public class DeviceAdminAdd extends Activity { } if (!mRefreshing && !mAddingProfileOwner && mDPM.isAdminActive(mDeviceAdmin.getComponent())) { - if (mActivePolicies.size() == 0) { - ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies(); - for (int i=0; i<policies.size(); i++) { - DeviceAdminInfo.PolicyInfo pi = policies.get(i); - View view = AppSecurityPermissions.getPermissionItemView( - this, getText(pi.label), "", true); - mActivePolicies.add(view); - mAdminPolicies.addView(view); - } - } - setViewVisibility(mActivePolicies, View.VISIBLE); - setViewVisibility(mAddingPolicies, View.GONE); + addDeviceAdminPolicies(false /* showDescription */); mAdminWarning.setText(getString(R.string.device_admin_status, mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager()))); setTitle(getText(R.string.active_device_admin_msg)); mActionButton.setText(getText(R.string.remove_device_admin)); mAdding = false; } else { - if (mAddingPolicies.size() == 0) { - ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies(); - for (int i=0; i<policies.size(); i++) { - DeviceAdminInfo.PolicyInfo pi = policies.get(i); - View view = AppSecurityPermissions.getPermissionItemView( - this, getText(pi.label), getText(pi.description), true); - mAddingPolicies.add(view); - mAdminPolicies.addView(view); - } - } - setViewVisibility(mAddingPolicies, View.VISIBLE); - setViewVisibility(mActivePolicies, View.GONE); + addDeviceAdminPolicies(true /* showDescription */); mAdminWarning.setText(getString(R.string.device_admin_warning, mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager()))); if (mAddingProfileOwner) { @@ -480,6 +448,19 @@ public class DeviceAdminAdd extends Activity { } } + private void addDeviceAdminPolicies(boolean showDescription) { + if (!mAdminPoliciesInitialized) { + boolean isOwner = UserHandle.getCallingUserHandle().isOwner(); + for (DeviceAdminInfo.PolicyInfo pi : mDeviceAdmin.getUsedPolicies()) { + int descriptionId = isOwner ? pi.description : pi.descriptionForSecondaryUsers; + int labelId = isOwner ? pi.label : pi.labelForSecondaryUsers; + View view = AppSecurityPermissions.getPermissionItemView(this, getText(labelId), + showDescription ? getText(descriptionId) : "", true); + mAdminPolicies.addView(view); + } + mAdminPoliciesInitialized = true; + } + } void toggleMessageEllipsis(View v) { TextView tv = (TextView) v; diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java index 334d18f..0e3dc42 100644 --- a/src/com/android/settings/DeviceAdminSettings.java +++ b/src/com/android/settings/DeviceAdminSettings.java @@ -303,7 +303,7 @@ public class DeviceAdminSettings extends ListFragment { bindView(convertView, (DeviceAdminInfo) o); } else { if (convertView == null) { - convertView = newTitleView(parent); + convertView = Utils.inflateCategoryHeader(mInflater, parent); } final TextView title = (TextView) convertView.findViewById(android.R.id.title); title.setText((String)o); @@ -322,15 +322,6 @@ public class DeviceAdminSettings extends ListFragment { return v; } - private View newTitleView(ViewGroup parent) { - final TypedArray a = mInflater.getContext().obtainStyledAttributes(null, - com.android.internal.R.styleable.Preference, - com.android.internal.R.attr.preferenceCategoryStyle, 0); - final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, - 0); - return mInflater.inflate(resId, parent, false); - } - private void bindView(View view, DeviceAdminInfo item) { final Activity activity = getActivity(); ViewHolder vh = (ViewHolder) view.getTag(); diff --git a/src/com/android/settings/HotspotOffReceiver.java b/src/com/android/settings/HotspotOffReceiver.java index 3ab3f9d..06ced1f 100644 --- a/src/com/android/settings/HotspotOffReceiver.java +++ b/src/com/android/settings/HotspotOffReceiver.java @@ -6,6 +6,8 @@ import android.content.Context; import android.content.Intent; import android.net.wifi.WifiManager; +import com.android.settingslib.TetherUtil; + /** * This receiver catches when quick settings turns off the hotspot, so we can * cancel the alarm in that case. All other cancels are handled in tethersettings. @@ -18,7 +20,7 @@ public class HotspotOffReceiver extends BroadcastReceiver { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED) { // The hotspot has been turned off, we don't need to recheck tethering. - TetherService.cancelRecheckAlarmIfNecessary(context, TetherSettings.WIFI_TETHERING); + TetherService.cancelRecheckAlarmIfNecessary(context, TetherUtil.TETHERING_WIFI); } } } diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java index 2b086a6..18b51d9 100644 --- a/src/com/android/settings/MasterClear.java +++ b/src/com/android/settings/MasterClear.java @@ -209,7 +209,7 @@ public class MasterClear extends Fragment { .getAuthenticatorTypesAsUser(profileId); final int M = descs.length; - View titleView = newTitleView(contents, inflater); + View titleView = Utils.inflateCategoryHeader(inflater, contents); final TextView titleText = (TextView) titleView.findViewById(android.R.id.title); titleText.setText(userInfo.isManagedProfile() ? R.string.category_work : R.string.category_personal); @@ -275,13 +275,4 @@ public class MasterClear extends Fragment { establishInitialState(); return mContentView; } - - private View newTitleView(ViewGroup parent, LayoutInflater inflater) { - final TypedArray a = inflater.getContext().obtainStyledAttributes(null, - com.android.internal.R.styleable.Preference, - com.android.internal.R.attr.preferenceCategoryStyle, 0); - final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, - 0); - return inflater.inflate(resId, parent, false); - } } diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index c2990e5..e809bb5 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -72,10 +72,6 @@ public class SecuritySettings extends SettingsPreferenceFragment // Lock Settings private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; - private static final String KEY_BIOMETRIC_WEAK_IMPROVE_MATCHING = - "biometric_weak_improve_matching"; - private static final String KEY_BIOMETRIC_WEAK_LIVELINESS = "biometric_weak_liveliness"; - private static final String KEY_LOCK_ENABLED = "lockenabled"; private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; private static final String KEY_SECURITY_CATEGORY = "security_category"; private static final String KEY_DEVICE_ADMIN_CATEGORY = "device_admin_category"; @@ -85,8 +81,6 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents"; private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; - private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST = 124; - private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF = 125; private static final int CHANGE_TRUST_AGENT_SETTINGS = 126; // Misc Settings @@ -104,8 +98,8 @@ public class SecuritySettings extends SettingsPreferenceFragment // These switch preferences need special handling since they're not all stored in Settings. private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_LOCK_AFTER_TIMEOUT, - KEY_LOCK_ENABLED, KEY_VISIBLE_PATTERN, KEY_BIOMETRIC_WEAK_LIVELINESS, - KEY_POWER_INSTANTLY_LOCKS, KEY_SHOW_PASSWORD, KEY_TOGGLE_INSTALL_APPLICATIONS }; + KEY_VISIBLE_PATTERN, KEY_POWER_INSTANTLY_LOCKS, KEY_SHOW_PASSWORD, + KEY_TOGGLE_INSTALL_APPLICATIONS }; // Only allow one trust agent on the platform. private static final boolean ONLY_ONE_TRUST_AGENT = true; @@ -117,7 +111,6 @@ public class SecuritySettings extends SettingsPreferenceFragment private LockPatternUtils mLockPatternUtils; private ListPreference mLockAfter; - private SwitchPreference mBiometricWeakLiveliness; private SwitchPreference mVisiblePattern; private SwitchPreference mShowPassword; @@ -165,9 +158,6 @@ public class SecuritySettings extends SettingsPreferenceFragment } else { resid = R.xml.security_settings_chooser; } - } else if (lockPatternUtils.usingBiometricWeak() && - lockPatternUtils.isBiometricWeakInstalled()) { - resid = R.xml.security_settings_biometric_weak; } else { switch (lockPatternUtils.getKeyguardStoredPasswordQuality()) { case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: @@ -265,10 +255,6 @@ public class SecuritySettings extends SettingsPreferenceFragment updateLockAfterPreferenceSummary(); } - // biometric weak liveliness - mBiometricWeakLiveliness = - (SwitchPreference) root.findPreference(KEY_BIOMETRIC_WEAK_LIVELINESS); - // visible pattern mVisiblePattern = (SwitchPreference) root.findPreference(KEY_VISIBLE_PATTERN); @@ -284,15 +270,6 @@ public class SecuritySettings extends SettingsPreferenceFragment trustAgentPreference.getTitle())); } - // don't display visible pattern if biometric and backup is not pattern - if (resid == R.xml.security_settings_biometric_weak && - mLockPatternUtils.getKeyguardStoredPasswordQuality() != - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { - if (securityCategory != null && mVisiblePattern != null) { - securityCategory.removePreference(root.findPreference(KEY_VISIBLE_PATTERN)); - } - } - // Append the rest of the settings addPreferencesFromResource(R.xml.security_settings_misc); @@ -562,10 +539,6 @@ public class SecuritySettings extends SettingsPreferenceFragment createPreferenceHierarchy(); final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); - if (mBiometricWeakLiveliness != null) { - mBiometricWeakLiveliness.setChecked( - lockPatternUtils.isBiometricWeakLivelinessEnabled()); - } if (mVisiblePattern != null) { mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled()); } @@ -589,17 +562,6 @@ public class SecuritySettings extends SettingsPreferenceFragment if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) { startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); - } else if (KEY_BIOMETRIC_WEAK_IMPROVE_MATCHING.equals(key)) { - ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(this.getActivity(), this); - if (!helper.launchConfirmationActivity( - CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST, null, null)) { - // If this returns false, it means no password confirmation is required, so - // go ahead and start improve. - // Note: currently a backup is required for biometric_weak so this code path - // can't be reached, but is here in case things change in the future - startBiometricWeakImprove(); - } } else if (KEY_TRUST_AGENT.equals(key)) { ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this.getActivity(), this); @@ -623,19 +585,7 @@ public class SecuritySettings extends SettingsPreferenceFragment @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST && - resultCode == Activity.RESULT_OK) { - startBiometricWeakImprove(); - return; - } else if (requestCode == CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF && - resultCode == Activity.RESULT_OK) { - final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); - lockPatternUtils.setBiometricWeakLivelinessEnabled(false); - // Setting the mBiometricWeakLiveliness checked value to false is handled when onResume - // is called by grabbing the value from lockPatternUtils. We can't set it here - // because mBiometricWeakLiveliness could be null - return; - } else if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) { + if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) { if (mTrustAgentClickIntent != null) { startActivity(mTrustAgentClickIntent); mTrustAgentClickIntent = null; @@ -659,30 +609,8 @@ public class SecuritySettings extends SettingsPreferenceFragment Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e); } updateLockAfterPreferenceSummary(); - } else if (KEY_LOCK_ENABLED.equals(key)) { - lockPatternUtils.setLockPatternEnabled((Boolean) value); } else if (KEY_VISIBLE_PATTERN.equals(key)) { lockPatternUtils.setVisiblePatternEnabled((Boolean) value); - } else if (KEY_BIOMETRIC_WEAK_LIVELINESS.equals(key)) { - if ((Boolean) value) { - lockPatternUtils.setBiometricWeakLivelinessEnabled(true); - } else { - // In this case the user has just unchecked the checkbox, but this action requires - // them to confirm their password. We need to re-check the checkbox until - // they've confirmed their password - mBiometricWeakLiveliness.setChecked(true); - ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(this.getActivity(), this); - if (!helper.launchConfirmationActivity( - CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF, null, null)) { - // If this returns false, it means no password confirmation is required, so - // go ahead and uncheck it here. - // Note: currently a backup is required for biometric_weak so this code path - // can't be reached, but is here in case things change in the future - lockPatternUtils.setBiometricWeakLivelinessEnabled(false); - mBiometricWeakLiveliness.setChecked(false); - } - } } else if (KEY_POWER_INSTANTLY_LOCKS.equals(key)) { mLockPatternUtils.setPowerButtonInstantlyLocks((Boolean) value); } else if (KEY_SHOW_PASSWORD.equals(key)) { @@ -706,12 +634,6 @@ public class SecuritySettings extends SettingsPreferenceFragment return R.string.help_url_security; } - public void startBiometricWeakImprove(){ - Intent intent = new Intent(); - intent.setClassName("com.android.facelock", "com.android.facelock.AddToSetup"); - startActivity(intent); - } - /** * For Search. Please keep it in sync when updating "createPreferenceHierarchy()" */ @@ -832,13 +754,6 @@ public class SecuritySettings extends SettingsPreferenceFragment // Add options for lock/unlock screen int resId = getResIdForLockUnlockScreen(context, lockPatternUtils); - // don't display visible pattern if biometric and backup is not pattern - if (resId == R.xml.security_settings_biometric_weak && - lockPatternUtils.getKeyguardStoredPasswordQuality() != - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { - keys.add(KEY_VISIBLE_PATTERN); - } - // Do not display SIM lock for devices without an Icc card TelephonyManager tm = TelephonyManager.getDefault(); if (!mIsPrimary || !tm.hasIccCard()) { diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 84bf615..d41c387 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -97,7 +97,6 @@ public class Settings extends SettingsActivity { public static class NotificationAppListActivity extends SettingsActivity { /* empty */ } public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class OtherSoundSettingsActivity extends SettingsActivity { /* empty */ } - public static class QuickLaunchSettingsActivity extends SettingsActivity { /* empty */ } public static class TopLevelSettings extends SettingsActivity { /* empty */ } public static class ApnSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index dc5675c..415de5b 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -83,7 +83,6 @@ import com.android.settings.fuelgauge.BatterySaverSettings; import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.notification.NotificationAppList; import com.android.settings.notification.OtherSoundSettings; -import com.android.settings.quicklaunch.QuickLaunchSettings; import com.android.settings.search.DynamicIndexableContentMonitor; import com.android.settings.search.Index; import com.android.settings.inputmethod.InputMethodAndLanguageSettings; @@ -301,7 +300,6 @@ public class SettingsActivity extends Activity NotificationAppList.class.getName(), AppNotificationSettings.class.getName(), OtherSoundSettings.class.getName(), - QuickLaunchSettings.class.getName(), ApnSettings.class.getName() }; diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java index 42e2baa..94ff8d6 100644 --- a/src/com/android/settings/SetupChooseLockGeneric.java +++ b/src/com/android/settings/SetupChooseLockGeneric.java @@ -94,16 +94,23 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric SetupWizardUtils.setHeaderText(getActivity(), getActivity().getTitle()); } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode != RESULT_CANCELED) { + super.onActivityResult(requestCode, resultCode, data); + } + // If the started activity was cancelled (e.g. the user presses back), then this + // activity will be resumed to foreground. + } + /*** * Disables preferences that are less secure than required quality and shows only secure * screen lock options here. * * @param quality the requested quality. - * @param allowBiometric whether to allow biometic screen lock */ @Override - protected void disableUnusablePreferences(final int quality, - MutableBoolean allowBiometric) { + protected void disableUnusablePreferences(final int quality) { // At this part of the flow, the user has already indicated they want to add a pin, // pattern or password, so don't show "None" or "Slide". We disable them here and set // the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard. @@ -111,24 +118,23 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric // installed with a policy we need to honor. final int newQuality = Math.max(quality, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - super.disableUnusablePreferencesImpl(newQuality, allowBiometric, - true /* hideDisabled */); + super.disableUnusablePreferencesImpl(newQuality, true /* hideDisabled */); } @Override - protected Intent getLockPasswordIntent(Context context, int quality, boolean isFallback, + protected Intent getLockPasswordIntent(Context context, int quality, int minLength, int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials) { final Intent intent = SetupChooseLockPassword.createIntent(context, quality, - isFallback, minLength, maxLength, requirePasswordToDecrypt, confirmCredentials); + minLength, maxLength, requirePasswordToDecrypt, confirmCredentials); SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); return intent; } @Override - protected Intent getLockPatternIntent(Context context, boolean isFallback, + protected Intent getLockPatternIntent(Context context, boolean requirePassword, boolean confirmCredentials) { - final Intent intent = SetupChooseLockPattern.createIntent(context, isFallback, + final Intent intent = SetupChooseLockPattern.createIntent(context, requirePassword, confirmCredentials); SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); return intent; diff --git a/src/com/android/settings/SetupChooseLockPassword.java b/src/com/android/settings/SetupChooseLockPassword.java index 4274205..b9f408e 100644 --- a/src/com/android/settings/SetupChooseLockPassword.java +++ b/src/com/android/settings/SetupChooseLockPassword.java @@ -38,10 +38,10 @@ import android.view.WindowInsets; public class SetupChooseLockPassword extends ChooseLockPassword implements SetupWizardNavBar.NavigationBarListener { - public static Intent createIntent(Context context, int quality, final boolean isFallback, + public static Intent createIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials) { - Intent intent = ChooseLockPassword.createIntent(context, quality, isFallback, minLength, + Intent intent = ChooseLockPassword.createIntent(context, quality, minLength, maxLength, requirePasswordToDecrypt, confirmCredentials); intent.setClass(context, SetupChooseLockPassword.class); intent.putExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false); diff --git a/src/com/android/settings/SetupChooseLockPattern.java b/src/com/android/settings/SetupChooseLockPattern.java index 7f2480b..903a207 100644 --- a/src/com/android/settings/SetupChooseLockPattern.java +++ b/src/com/android/settings/SetupChooseLockPattern.java @@ -38,9 +38,9 @@ import android.widget.Button; public class SetupChooseLockPattern extends ChooseLockPattern implements SetupWizardNavBar.NavigationBarListener { - public static Intent createIntent(Context context, final boolean isFallback, + public static Intent createIntent(Context context, boolean requirePassword, boolean confirmCredentials) { - Intent intent = ChooseLockPattern.createIntent(context, isFallback, requirePassword, + Intent intent = ChooseLockPattern.createIntent(context, requirePassword, confirmCredentials); intent.setClass(context, SetupChooseLockPattern.class); return intent; diff --git a/src/com/android/settings/SetupRedactionInterstitial.java b/src/com/android/settings/SetupRedactionInterstitial.java index 453e729..badfe8d 100644 --- a/src/com/android/settings/SetupRedactionInterstitial.java +++ b/src/com/android/settings/SetupRedactionInterstitial.java @@ -67,6 +67,7 @@ public class SetupRedactionInterstitial extends RedactionInterstitial @Override public void onNavigationBarCreated(SetupWizardNavBar bar) { SetupWizardUtils.setImmersiveMode(this, bar); + bar.getBackButton().setEnabled(false); } @Override diff --git a/src/com/android/settings/TetherService.java b/src/com/android/settings/TetherService.java index 9323c33..03bcc83 100644 --- a/src/com/android/settings/TetherService.java +++ b/src/com/android/settings/TetherService.java @@ -37,6 +37,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.settings.wifi.WifiApEnabler; +import com.android.settingslib.TetherUtil; import java.util.ArrayList; @@ -44,12 +45,6 @@ public class TetherService extends Service { private static final String TAG = "TetherService"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; - public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; - public static final String EXTRA_SET_ALARM = "extraSetAlarm"; - public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; - public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether"; - private static final String EXTRA_RESULT = "EntitlementResult"; // Activity results to match the activity provision protocol. @@ -88,15 +83,17 @@ public class TetherService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (intent.hasExtra(EXTRA_ADD_TETHER_TYPE)) { - int type = intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TetherSettings.INVALID); + if (intent.hasExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE)) { + int type = intent.getIntExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE, + TetherUtil.TETHERING_INVALID); if (!mCurrentTethers.contains(type)) { if (DEBUG) Log.d(TAG, "Adding tether " + type); mCurrentTethers.add(type); } } - if (intent.hasExtra(EXTRA_REM_TETHER_TYPE)) { - int type = intent.getIntExtra(EXTRA_REM_TETHER_TYPE, TetherSettings.INVALID); + if (intent.hasExtra(TetherUtil.EXTRA_REM_TETHER_TYPE)) { + int type = intent.getIntExtra(TetherUtil.EXTRA_REM_TETHER_TYPE, + TetherUtil.TETHERING_INVALID); if (DEBUG) Log.d(TAG, "Removing tether " + type); int index = mCurrentTethers.indexOf(type); if (index >= 0) { @@ -112,16 +109,16 @@ public class TetherService extends Service { // Only set the alarm if we have one tether, meaning the one just added, // to avoid setting it when it was already set previously for another // type. - if (intent.getBooleanExtra(EXTRA_SET_ALARM, false) + if (intent.getBooleanExtra(TetherUtil.EXTRA_SET_ALARM, false) && mCurrentTethers.size() == 1) { scheduleAlarm(); } - if (intent.getBooleanExtra(EXTRA_ENABLE_WIFI_TETHER, false)) { + if (intent.getBooleanExtra(TetherUtil.EXTRA_ENABLE_WIFI_TETHER, false)) { mEnableWifiAfterCheck = true; } - if (intent.getBooleanExtra(EXTRA_RUN_PROVISION, false)) { + if (intent.getBooleanExtra(TetherUtil.EXTRA_RUN_PROVISION, false)) { startProvisioning(mCurrentTypeIndex); } else if (!mInProvisionCheck) { // If we aren't running any provisioning, no reason to stay alive. @@ -172,14 +169,13 @@ public class TetherService extends Service { } private void enableWifiTetheringIfNeeded() { - if (!isHotspotEnabled(this)) { - new WifiApEnabler(this, null).setSoftapEnabled(true); + if (!TetherUtil.isWifiTetherEnabled(this)) { + TetherUtil.setWifiTethering(true, this); } } private void disableWifiTethering() { - WifiApEnabler enabler = new WifiApEnabler(this, null); - enabler.setSoftapEnabled(false); + TetherUtil.setWifiTethering(false, this); } private void disableUsbTethering() { @@ -216,21 +212,16 @@ public class TetherService extends Service { mInProvisionCheck = true; } - private static boolean isHotspotEnabled(Context context) { - WifiManager wifiManager = (WifiManager) context.getSystemService(WIFI_SERVICE); - return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED; - } - public static void scheduleRecheckAlarm(Context context, int type) { Intent intent = new Intent(context, TetherService.class); - intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); - intent.putExtra(EXTRA_SET_ALARM, true); + intent.putExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE, type); + intent.putExtra(TetherUtil.EXTRA_SET_ALARM, true); context.startService(intent); } private void scheduleAlarm() { Intent intent = new Intent(this, TetherService.class); - intent.putExtra(EXTRA_RUN_PROVISION, true); + intent.putExtra(TetherUtil.EXTRA_RUN_PROVISION, true); PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); @@ -250,7 +241,7 @@ public class TetherService extends Service { */ public static void cancelRecheckAlarmIfNecessary(final Context context, int type) { Intent intent = new Intent(context, TetherService.class); - intent.putExtra(EXTRA_REM_TETHER_TYPE, type); + intent.putExtra(TetherUtil.EXTRA_REM_TETHER_TYPE, type); context.startService(intent); } @@ -276,19 +267,19 @@ public class TetherService extends Service { mInProvisionCheck = false; int checkType = mCurrentTethers.get(mCurrentTypeIndex); if (intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT) == RESULT_OK) { - if (checkType == TetherSettings.WIFI_TETHERING && mEnableWifiAfterCheck) { + if (checkType == TetherUtil.TETHERING_WIFI && mEnableWifiAfterCheck) { enableWifiTetheringIfNeeded(); mEnableWifiAfterCheck = false; } } else { switch (checkType) { - case TetherSettings.WIFI_TETHERING: + case TetherUtil.TETHERING_WIFI: disableWifiTethering(); break; - case TetherSettings.BLUETOOTH_TETHERING: + case TetherUtil.TETHERING_BLUETOOTH: disableBtTethering(); break; - case TetherSettings.USB_TETHERING: + case TetherUtil.TETHERING_USB: disableUsbTethering(); break; } diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java index e33ddb0..393adf6 100644 --- a/src/com/android/settings/TetherSettings.java +++ b/src/com/android/settings/TetherSettings.java @@ -16,6 +16,11 @@ package com.android.settings; +import static com.android.settingslib.TetherUtil.TETHERING_INVALID; +import static com.android.settingslib.TetherUtil.TETHERING_WIFI; +import static com.android.settingslib.TetherUtil.TETHERING_USB; +import static com.android.settingslib.TetherUtil.TETHERING_BLUETOOTH; + import android.app.Activity; import android.app.Dialog; import android.bluetooth.BluetoothAdapter; @@ -43,6 +48,7 @@ import android.widget.TextView; import com.android.settings.wifi.WifiApDialog; import com.android.settings.wifi.WifiApEnabler; +import com.android.settingslib.TetherUtil; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; @@ -93,13 +99,8 @@ public class TetherSettings extends SettingsPreferenceFragment private boolean mBluetoothEnableForTether; - public static final int INVALID = -1; - public static final int WIFI_TETHERING = 0; - public static final int USB_TETHERING = 1; - public static final int BLUETOOTH_TETHERING = 2; - /* One of INVALID, WIFI_TETHERING, USB_TETHERING or BLUETOOTH_TETHERING */ - private int mTetherChoice = INVALID; + private int mTetherChoice = TETHERING_INVALID; /* Stores the package name and the class name of the provisioning app */ private String[] mProvisionApp; @@ -454,10 +455,10 @@ public class TetherSettings extends SettingsPreferenceFragment boolean enable = (Boolean) value; if (enable) { - startProvisioningIfNecessary(WIFI_TETHERING); + startProvisioningIfNecessary(TETHERING_WIFI); } else { - if (isProvisioningNeeded(mProvisionApp)) { - TetherService.cancelRecheckAlarmIfNecessary(getActivity(), WIFI_TETHERING); + if (TetherUtil.isProvisioningNeeded(getActivity())) { + TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_WIFI); } mWifiApEnabler.setSoftapEnabled(false); } @@ -465,16 +466,13 @@ public class TetherSettings extends SettingsPreferenceFragment } public static boolean isProvisioningNeededButUnavailable(Context context) { - String[] provisionApp = context.getResources().getStringArray( - com.android.internal.R.array.config_mobile_hotspot_provision_app); - return (isProvisioningNeeded(provisionApp) - && !isIntentAvailable(context, provisionApp)); + return (TetherUtil.isProvisioningNeeded(context) + && !isIntentAvailable(context)); } - private static boolean isIntentAvailable(Context context, String[] provisionApp) { - if (provisionApp.length < 2) { - throw new IllegalArgumentException("provisionApp length should at least be 2"); - } + private static boolean isIntentAvailable(Context context) { + String[] provisionApp = context.getResources().getStringArray( + com.android.internal.R.array.config_mobile_hotspot_provision_app); final PackageManager packageManager = context.getPackageManager(); Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); @@ -483,18 +481,9 @@ public class TetherSettings extends SettingsPreferenceFragment PackageManager.MATCH_DEFAULT_ONLY).size() > 0); } - - private static boolean isProvisioningNeeded(String[] provisionApp) { - if (SystemProperties.getBoolean("net.tethering.noprovisioning", false) - || provisionApp == null) { - return false; - } - return (provisionApp.length == 2); - } - private void startProvisioningIfNecessary(int choice) { mTetherChoice = choice; - if (isProvisioningNeeded(mProvisionApp)) { + if (TetherUtil.isProvisioningNeeded(getActivity())) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(mProvisionApp[0], mProvisionApp[1]); intent.putExtra(TETHER_CHOICE, mTetherChoice); @@ -514,24 +503,24 @@ public class TetherSettings extends SettingsPreferenceFragment //BT and USB need switch turned off on failure //Wifi tethering is never turned on until afterwards switch (mTetherChoice) { - case BLUETOOTH_TETHERING: + case TETHERING_BLUETOOTH: mBluetoothTether.setChecked(false); break; - case USB_TETHERING: + case TETHERING_USB: mUsbTether.setChecked(false); break; } - mTetherChoice = INVALID; + mTetherChoice = TETHERING_INVALID; } } } private void startTethering() { switch (mTetherChoice) { - case WIFI_TETHERING: + case TETHERING_WIFI: mWifiApEnabler.setSoftapEnabled(true); break; - case BLUETOOTH_TETHERING: + case TETHERING_BLUETOOTH: // turn on Bluetooth first BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter.getState() == BluetoothAdapter.STATE_OFF) { @@ -545,7 +534,7 @@ public class TetherSettings extends SettingsPreferenceFragment mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext); } break; - case USB_TETHERING: + case TETHERING_USB: setUsbTethering(true); break; default: @@ -574,10 +563,10 @@ public class TetherSettings extends SettingsPreferenceFragment boolean newState = mUsbTether.isChecked(); if (newState) { - startProvisioningIfNecessary(USB_TETHERING); + startProvisioningIfNecessary(TETHERING_USB); } else { - if (isProvisioningNeeded(mProvisionApp)) { - TetherService.cancelRecheckAlarmIfNecessary(getActivity(), USB_TETHERING); + if (TetherUtil.isProvisioningNeeded(getActivity())) { + TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_USB); } setUsbTethering(newState); } @@ -585,10 +574,10 @@ public class TetherSettings extends SettingsPreferenceFragment boolean bluetoothTetherState = mBluetoothTether.isChecked(); if (bluetoothTetherState) { - startProvisioningIfNecessary(BLUETOOTH_TETHERING); + startProvisioningIfNecessary(TETHERING_BLUETOOTH); } else { - if (isProvisioningNeeded(mProvisionApp)) { - TetherService.cancelRecheckAlarmIfNecessary(getActivity(), BLUETOOTH_TETHERING); + if (TetherUtil.isProvisioningNeeded(getActivity())) { + TetherService.cancelRecheckAlarmIfNecessary(getActivity(), TETHERING_BLUETOOTH); } boolean errored = false; @@ -652,17 +641,4 @@ public class TetherSettings extends SettingsPreferenceFragment public int getHelpResource() { return R.string.help_url_tether; } - - /** - * Checks whether this screen will have anything to show on this device. This is called by - * the shortcut picker for Settings shortcuts (home screen widget). - * @param context a context object for getting a system service. - * @return whether Tether & portable hotspot should be shown in the shortcuts picker. - */ - public static boolean showInShortcuts(Context context) { - final ConnectivityManager cm = - (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); - final boolean isSecondaryUser = UserHandle.myUserId() != UserHandle.USER_OWNER; - return !isSecondaryUser && cm.isTetheringSupported(); - } } diff --git a/src/com/android/settings/TrustedCredentialsSettings.java b/src/com/android/settings/TrustedCredentialsSettings.java index e2b49d6..95a6bf4 100644 --- a/src/com/android/settings/TrustedCredentialsSettings.java +++ b/src/com/android/settings/TrustedCredentialsSettings.java @@ -321,7 +321,7 @@ public class TrustedCredentialsSettings extends Fragment { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getActivity() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflateCategoryHeader(inflater, parent); + convertView = Utils.inflateCategoryHeader(inflater, parent); } final TextView title = (TextView) convertView.findViewById(android.R.id.title); @@ -354,15 +354,6 @@ public class TrustedCredentialsSettings extends Fragment { public int getListViewId(Tab tab) { return tab.mExpandableList; } - private View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) { - final TypedArray a = inflater.getContext().obtainStyledAttributes(null, - com.android.internal.R.styleable.Preference, - com.android.internal.R.attr.preferenceCategoryStyle, 0); - final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, - 0); - return inflater.inflate(resId, parent, false); - } - } private class TrustedCertificateAdapter extends BaseAdapter implements diff --git a/src/com/android/settings/UsageAccessSettings.java b/src/com/android/settings/UsageAccessSettings.java index 89e184e..fd98b51 100644 --- a/src/com/android/settings/UsageAccessSettings.java +++ b/src/com/android/settings/UsageAccessSettings.java @@ -17,6 +17,7 @@ package com.android.settings; import com.android.internal.content.PackageMonitor; +import com.android.settings.DataUsageSummary.AppItem; import android.Manifest; import android.app.ActivityThread; @@ -28,6 +29,7 @@ import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -35,18 +37,24 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceScreen; import android.preference.SwitchPreference; import android.util.ArrayMap; +import android.util.AttributeSet; import android.util.Log; +import android.util.SparseArray; import java.util.List; +import java.util.Collections; public class UsageAccessSettings extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener { private static final String TAG = "UsageAccessSettings"; + private static final String BUNDLE_KEY_PROFILEID = "profileId"; private static final String[] PM_USAGE_STATS_PERMISSION = new String[] { Manifest.permission.PACKAGE_USAGE_STATS @@ -56,16 +64,23 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements AppOpsManager.OP_GET_USAGE_STATS }; - private static class PackageEntry { - public PackageEntry(String packageName) { + private static class PackageEntry implements Comparable<PackageEntry> { + public PackageEntry(String packageName, UserHandle userHandle) { this.packageName = packageName; this.appOpMode = AppOpsManager.MODE_DEFAULT; + this.userHandle = userHandle; + } + + @Override + public int compareTo(PackageEntry another) { + return packageName.compareTo(another.packageName); } final String packageName; PackageInfo packageInfo; boolean permissionGranted; int appOpMode; + UserHandle userHandle; SwitchPreference preference; } @@ -75,69 +90,102 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements * the PreferenceScreen with the results when complete. */ private class AppsRequestingAccessFetcher extends - AsyncTask<Void, Void, ArrayMap<String, PackageEntry>> { + AsyncTask<Void, Void, SparseArray<ArrayMap<String, PackageEntry>>> { private final Context mContext; private final PackageManager mPackageManager; private final IPackageManager mIPackageManager; + private final UserManager mUserManager; + private final List<UserHandle> mProfiles; public AppsRequestingAccessFetcher(Context context) { mContext = context; mPackageManager = context.getPackageManager(); mIPackageManager = ActivityThread.getPackageManager(); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mProfiles = mUserManager.getUserProfiles(); } @Override - protected ArrayMap<String, PackageEntry> doInBackground(Void... params) { + protected SparseArray<ArrayMap<String, PackageEntry>> doInBackground(Void... params) { final String[] packages; + SparseArray<ArrayMap<String, PackageEntry>> entries; try { packages = mIPackageManager.getAppOpPermissionPackages( Manifest.permission.PACKAGE_USAGE_STATS); + + if (packages == null) { + // No packages are requesting permission to use the UsageStats API. + return null; + } + + entries = new SparseArray<>(); + for (final UserHandle profile : mProfiles) { + final ArrayMap<String, PackageEntry> entriesForProfile = new ArrayMap<>(); + final int profileId = profile.getIdentifier(); + entries.put(profileId, entriesForProfile); + for (final String packageName : packages) { + final boolean isAvailable = mIPackageManager.isPackageAvailable(packageName, + profileId); + if (!shouldIgnorePackage(packageName) && isAvailable) { + final PackageEntry newEntry = new PackageEntry(packageName, profile); + entriesForProfile.put(packageName, newEntry); + } + } + } } catch (RemoteException e) { Log.w(TAG, "PackageManager is dead. Can't get list of packages requesting " + Manifest.permission.PACKAGE_USAGE_STATS); return null; } - if (packages == null) { - // No packages are requesting permission to use the UsageStats API. - return null; - } - - ArrayMap<String, PackageEntry> entries = new ArrayMap<>(); - for (final String packageName : packages) { - if (!shouldIgnorePackage(packageName)) { - entries.put(packageName, new PackageEntry(packageName)); - } - } - // Load the packages that have been granted the PACKAGE_USAGE_STATS permission. - final List<PackageInfo> packageInfos = mPackageManager.getPackagesHoldingPermissions( - PM_USAGE_STATS_PERMISSION, 0); - final int packageInfoCount = packageInfos != null ? packageInfos.size() : 0; - for (int i = 0; i < packageInfoCount; i++) { - final PackageInfo packageInfo = packageInfos.get(i); - final PackageEntry pe = entries.get(packageInfo.packageName); - if (pe != null) { - pe.packageInfo = packageInfo; - pe.permissionGranted = true; + try { + for (final UserHandle profile : mProfiles) { + final int profileId = profile.getIdentifier(); + final ArrayMap<String, PackageEntry> entriesForProfile = entries.get(profileId); + if (entriesForProfile == null) { + continue; + } + final List<PackageInfo> packageInfos = mIPackageManager + .getPackagesHoldingPermissions(PM_USAGE_STATS_PERMISSION, 0, profileId) + .getList(); + final int packageInfoCount = packageInfos != null ? packageInfos.size() : 0; + for (int i = 0; i < packageInfoCount; i++) { + final PackageInfo packageInfo = packageInfos.get(i); + final PackageEntry pe = entriesForProfile.get(packageInfo.packageName); + if (pe != null) { + pe.packageInfo = packageInfo; + pe.permissionGranted = true; + } + } } + } catch (RemoteException e) { + Log.w(TAG, "PackageManager is dead. Can't get list of packages granted " + + Manifest.permission.PACKAGE_USAGE_STATS); + return null; } // Load the remaining packages that have requested but don't have the // PACKAGE_USAGE_STATS permission. - int packageCount = entries.size(); - for (int i = 0; i < packageCount; i++) { - final PackageEntry pe = entries.valueAt(i); - if (pe.packageInfo == null) { - try { - pe.packageInfo = mPackageManager.getPackageInfo(pe.packageName, 0); - } catch (PackageManager.NameNotFoundException e) { - // This package doesn't exist. This may occur when an app is uninstalled for - // one user, but it is not removed from the system. - entries.removeAt(i); - i--; - packageCount--; + for (final UserHandle profile : mProfiles) { + final int profileId = profile.getIdentifier(); + final ArrayMap<String, PackageEntry> entriesForProfile = entries.get(profileId); + if (entriesForProfile == null) { + continue; + } + int packageCount = entriesForProfile.size(); + for (int i = packageCount - 1; i >= 0; --i) { + final PackageEntry pe = entriesForProfile.valueAt(i); + if (pe.packageInfo == null) { + try { + pe.packageInfo = mIPackageManager.getPackageInfo(pe.packageName, 0, + profileId); + } catch (RemoteException e) { + // This package doesn't exist. This may occur when an app is + // uninstalled for one user, but it is not removed from the system. + entriesForProfile.removeAt(i); + } } } } @@ -148,15 +196,21 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements final int packageOpsCount = packageOps != null ? packageOps.size() : 0; for (int i = 0; i < packageOpsCount; i++) { final AppOpsManager.PackageOps packageOp = packageOps.get(i); - final PackageEntry pe = entries.get(packageOp.getPackageName()); - if (pe == null) { - Log.w(TAG, "AppOp permission exists for package " + packageOp.getPackageName() - + " but package doesn't exist or did not request UsageStats access"); + final int userId = UserHandle.getUserId(packageOp.getUid()); + if (!isThisUserAProfileOfCurrentUser(userId)) { + // This AppOp does not belong to any of this user's profiles. continue; } - if (packageOp.getUid() != pe.packageInfo.applicationInfo.uid) { - // This AppOp does not belong to this user. + final ArrayMap<String, PackageEntry> entriesForProfile = entries.get(userId); + if (entriesForProfile == null) { + continue; + } + final PackageEntry pe = entriesForProfile.get(packageOp.getPackageName()); + if (pe == null) { + Log.w(TAG, "AppOp permission exists for package " + packageOp.getPackageName() + + " of user " + userId + + " but package doesn't exist or did not request UsageStats access"); continue; } @@ -173,7 +227,7 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements } @Override - protected void onPostExecute(ArrayMap<String, PackageEntry> newEntries) { + protected void onPostExecute(SparseArray<ArrayMap<String, PackageEntry>> newEntries) { mLastFetcherTask = null; if (getActivity() == null) { @@ -188,41 +242,126 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements } // Find the deleted entries and remove them from the PreferenceScreen. - final int oldPackageCount = mPackageEntryMap.size(); - for (int i = 0; i < oldPackageCount; i++) { - final PackageEntry oldPackageEntry = mPackageEntryMap.valueAt(i); - final PackageEntry newPackageEntry = newEntries.get(oldPackageEntry.packageName); - if (newPackageEntry == null) { - // This package has been removed. - mPreferenceScreen.removePreference(oldPackageEntry.preference); - } else { - // This package already exists in the preference hierarchy, so reuse that - // Preference. - newPackageEntry.preference = oldPackageEntry.preference; + final int oldProfileCount = mPackageEntryMap.size(); + for (int profileIndex = 0; profileIndex < oldProfileCount; ++profileIndex) { + final int profileId = mPackageEntryMap.keyAt(profileIndex); + final ArrayMap<String, PackageEntry> oldEntriesForProfile = mPackageEntryMap + .valueAt(profileIndex); + final int oldPackageCount = oldEntriesForProfile.size(); + + final ArrayMap<String, PackageEntry> newEntriesForProfile = newEntries.get( + profileId); + + for (int i = 0; i < oldPackageCount; i++) { + final PackageEntry oldPackageEntry = oldEntriesForProfile.valueAt(i); + + PackageEntry newPackageEntry = null; + if (newEntriesForProfile != null) { + newPackageEntry = newEntriesForProfile.get(oldPackageEntry.packageName); + } + if (newPackageEntry == null) { + // This package has been removed. + mPreferenceScreen.removePreference(oldPackageEntry.preference); + } else { + // This package already exists in the preference hierarchy, so reuse that + // Preference. + newPackageEntry.preference = oldPackageEntry.preference; + } } } // Now add new packages to the PreferenceScreen. - final int packageCount = newEntries.size(); - for (int i = 0; i < packageCount; i++) { - final PackageEntry packageEntry = newEntries.valueAt(i); - if (packageEntry.preference == null) { - packageEntry.preference = new SwitchPreference(mContext); - packageEntry.preference.setPersistent(false); - packageEntry.preference.setOnPreferenceChangeListener(UsageAccessSettings.this); - mPreferenceScreen.addPreference(packageEntry.preference); + final int newProfileCount = newEntries.size(); + for (int profileIndex = 0; profileIndex < newProfileCount; ++profileIndex) { + final int profileId = newEntries.keyAt(profileIndex); + final ArrayMap<String, PackageEntry> newEntriesForProfile = newEntries.get( + profileId); + final int packageCount = newEntriesForProfile.size(); + for (int i = 0; i < packageCount; i++) { + final PackageEntry packageEntry = newEntriesForProfile.valueAt(i); + if (packageEntry.preference == null) { + packageEntry.preference = new SwitchPreference(mContext); + packageEntry.preference.setPersistent(false); + packageEntry.preference.setOnPreferenceChangeListener( + UsageAccessSettings.this); + mPreferenceScreen.addPreference(packageEntry.preference); + } + updatePreference(packageEntry); } - updatePreference(packageEntry); } - mPackageEntryMap.clear(); mPackageEntryMap = newEntries; + + // Add/remove headers if necessary. If there are package entries only for one user and + // that user is not the managed profile then do not show headers. + if (mPackageEntryMap.size() == 1 && + mPackageEntryMap.keyAt(0) == UserHandle.myUserId()) { + for (int i = 0; i < mCategoryHeaders.length; ++i) { + if (mCategoryHeaders[i] != null) { + mPreferenceScreen.removePreference(mCategoryHeaders[i]); + } + mCategoryHeaders[i] = null; + } + } else { + for (int i = 0; i < mCategoryHeaders.length; ++i) { + if (mCategoryHeaders[i] == null) { + final Preference preference = new Preference(mContext, null, + com.android.internal.R.attr.preferenceCategoryStyle, 0); + mCategoryHeaders[i] = preference; + preference.setTitle(mCategoryHeaderTitleResIds[i]); + preference.setEnabled(false); + mPreferenceScreen.addPreference(preference); + } + } + } + + // Sort preferences alphabetically within categories + int order = 0; + final int profileCount = mProfiles.size(); + for (int i = 0; i < profileCount; ++i) { + Preference header = mCategoryHeaders[i]; + if (header != null) { + header.setOrder(order++); + } + ArrayMap<String, PackageEntry> entriesForProfile = + mPackageEntryMap.get(mProfiles.get(i).getIdentifier()); + if (entriesForProfile != null) { + List<PackageEntry> sortedEntries = Collections.list( + Collections.enumeration(entriesForProfile.values())); + Collections.sort(sortedEntries); + for (PackageEntry pe : sortedEntries) { + pe.preference.setOrder(order++); + } + } + } } private void updatePreference(PackageEntry pe) { - pe.preference.setIcon(pe.packageInfo.applicationInfo.loadIcon(mPackageManager)); - pe.preference.setTitle(pe.packageInfo.applicationInfo.loadLabel(mPackageManager)); + final int profileId = pe.userHandle.getIdentifier(); + // Set something as default + pe.preference.setEnabled(false); + pe.preference.setTitle(pe.packageName); + pe.preference.setIcon(mUserManager.getBadgedIconForUser(mPackageManager + .getDefaultActivityIcon(), pe.userHandle)); + try { + // Try setting real title and icon + final ApplicationInfo info = mIPackageManager.getApplicationInfo(pe.packageName, + 0 /* no flags */, profileId); + if (info != null) { + pe.preference.setEnabled(true); + pe.preference.setTitle(info.loadLabel(mPackageManager).toString()); + pe.preference.setIcon(mUserManager.getBadgedIconForUser(info.loadIcon( + mPackageManager), pe.userHandle)); + } + } catch (RemoteException e) { + Log.w(TAG, "PackageManager is dead. Can't get app info for package " + + pe.packageName + " of user " + profileId); + // Keep going to update other parts of the preference + } + pe.preference.setKey(pe.packageName); + Bundle extra = pe.preference.getExtras(); + extra.putInt(BUNDLE_KEY_PROFILEID, profileId); boolean check = false; if (pe.appOpMode == AppOpsManager.MODE_ALLOWED) { @@ -237,6 +376,16 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements pe.preference.setChecked(check); } } + + private boolean isThisUserAProfileOfCurrentUser(final int userId) { + final int profilesMax = mProfiles.size(); + for (int i = 0; i < profilesMax; ++i) { + if (mProfiles.get(i).getIdentifier() == userId) { + return true; + } + } + return false; + } } static boolean shouldIgnorePackage(String packageName) { @@ -244,9 +393,14 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements } private AppsRequestingAccessFetcher mLastFetcherTask; - ArrayMap<String, PackageEntry> mPackageEntryMap = new ArrayMap<>(); + SparseArray<ArrayMap<String, PackageEntry>> mPackageEntryMap = new SparseArray<>(); AppOpsManager mAppOpsManager; PreferenceScreen mPreferenceScreen; + private Preference[] mCategoryHeaders = new Preference[2]; + private static int[] mCategoryHeaderTitleResIds = new int[] { + R.string.category_personal, + R.string.category_work + }; @Override public void onCreate(Bundle icicle) { @@ -293,16 +447,16 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final String packageName = preference.getKey(); - final PackageEntry pe = mPackageEntryMap.get(packageName); + final int profileId = preference.getExtras().getInt(BUNDLE_KEY_PROFILEID); + final PackageEntry pe = getPackageEntry(packageName, profileId); if (pe == null) { - Log.w(TAG, "Preference change event for package " + packageName - + " but that package is no longer valid."); + Log.w(TAG, "Preference change event handling failed"); return false; } if (!(newValue instanceof Boolean)) { - Log.w(TAG, "Preference change event for package " + packageName - + " had non boolean value of type " + newValue.getClass().getName()); + Log.w(TAG, "Preference change event for package " + packageName + " of user " + + profileId + " had non boolean value of type " + newValue.getClass().getName()); return false; } @@ -323,7 +477,7 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements if (prev != null) { ft.remove(prev); } - WarningDialogFragment.newInstance(pe.packageName).show(ft, "warning"); + WarningDialogFragment.newInstance(pe).show(ft, "warning"); return false; } return true; @@ -335,10 +489,10 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements pe.appOpMode = newMode; } - void allowAccess(String packageName) { - final PackageEntry entry = mPackageEntryMap.get(packageName); + void allowAccess(String packageName, int profileId) { + final PackageEntry entry = getPackageEntry(packageName, profileId); if (entry == null) { - Log.w(TAG, "Unable to give access to package " + packageName + ": it does not exist."); + Log.w(TAG, "Unable to give access"); return; } @@ -346,6 +500,21 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements entry.preference.setChecked(true); } + private PackageEntry getPackageEntry(String packageName, int profileId) { + ArrayMap<String, PackageEntry> entriesForProfile = mPackageEntryMap.get(profileId); + if (entriesForProfile == null) { + Log.w(TAG, "getPackageEntry fails for package " + packageName + " of user " + + profileId + ": user does not seem to be valid."); + return null; + } + final PackageEntry entry = entriesForProfile.get(packageName); + if (entry == null) { + Log.w(TAG, "getPackageEntry fails for package " + packageName + " of user " + + profileId + ": package does not exist."); + } + return entry; + } + private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public void onPackageAdded(String packageName, int uid) { @@ -361,11 +530,13 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements public static class WarningDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { private static final String ARG_PACKAGE_NAME = "package"; + private static final String ARG_PROFILE_ID = "profileId"; - public static WarningDialogFragment newInstance(String packageName) { + public static WarningDialogFragment newInstance(PackageEntry pe) { WarningDialogFragment dialog = new WarningDialogFragment(); Bundle args = new Bundle(); - args.putString(ARG_PACKAGE_NAME, packageName); + args.putString(ARG_PACKAGE_NAME, pe.packageName); + args.putInt(ARG_PROFILE_ID, pe.userHandle.getIdentifier()); dialog.setArguments(args); return dialog; } @@ -385,7 +556,8 @@ public class UsageAccessSettings extends SettingsPreferenceFragment implements public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { ((UsageAccessSettings) getParentFragment()).allowAccess( - getArguments().getString(ARG_PACKAGE_NAME)); + getArguments().getString(ARG_PACKAGE_NAME), + getArguments().getInt(ARG_PROFILE_ID)); } else { dialog.cancel(); } diff --git a/src/com/android/settings/UserSpinnerAdapter.java b/src/com/android/settings/UserSpinnerAdapter.java index eb4a118..5e2b16f 100644 --- a/src/com/android/settings/UserSpinnerAdapter.java +++ b/src/com/android/settings/UserSpinnerAdapter.java @@ -32,6 +32,7 @@ import android.widget.SpinnerAdapter; import android.widget.TextView; import com.android.internal.util.UserIcons; +import com.android.settings.drawable.CircleFramedDrawable; import java.util.ArrayList; @@ -43,18 +44,19 @@ public class UserSpinnerAdapter implements SpinnerAdapter { /** Holder for user details */ public static class UserDetails { private final UserHandle mUserHandle; - private final String name; - private final Drawable icon; + private final String mName; + private final Drawable mIcon; public UserDetails(UserHandle userHandle, UserManager um, Context context) { mUserHandle = userHandle; UserInfo userInfo = um.getUserInfo(mUserHandle.getIdentifier()); + Drawable icon; if (userInfo.isManagedProfile()) { - name = context.getString(R.string.managed_user_title); + mName = context.getString(R.string.managed_user_title); icon = context.getDrawable( com.android.internal.R.drawable.ic_corp_icon); } else { - name = userInfo.name; + mName = userInfo.name; final int userId = userInfo.id; if (um.getUserIcon(userId) != null) { icon = new BitmapDrawable(context.getResources(), um.getUserIcon(userId)); @@ -62,6 +64,11 @@ public class UserSpinnerAdapter implements SpinnerAdapter { icon = UserIcons.getDefaultUserIcon(userId, /* light= */ false); } } + this.mIcon = encircle(context, icon); + } + + private static Drawable encircle(Context context, Drawable icon) { + return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(icon)); } } private ArrayList<UserDetails> data; @@ -87,8 +94,8 @@ public class UserSpinnerAdapter implements SpinnerAdapter { final View row = convertView != null ? convertView : createUser(parent); UserDetails user = data.get(position); - ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(user.icon); - ((TextView) row.findViewById(android.R.id.title)).setText(user.name); + ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(user.mIcon); + ((TextView) row.findViewById(android.R.id.title)).setText(user.mName); return row; } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 6517ffe..9257c30 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -37,6 +37,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.res.Resources; +import android.content.res.TypedArray; import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.graphics.Bitmap; @@ -65,6 +66,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; @@ -846,43 +848,6 @@ public final class Utils { || um.getUserProfiles().contains(otherUser); } - /** - * Creates a dialog to confirm with the user if it's ok to remove the user - * and delete all the data. - * - * @param context a Context object - * @param removingUserId The userId of the user to remove - * @param onConfirmListener Callback object for positive action - * @return the created Dialog - */ - public static Dialog createRemoveConfirmationDialog(Context context, int removingUserId, - DialogInterface.OnClickListener onConfirmListener) { - UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); - UserInfo userInfo = um.getUserInfo(removingUserId); - int titleResId; - int messageResId; - if (UserHandle.myUserId() == removingUserId) { - titleResId = R.string.user_confirm_remove_self_title; - messageResId = R.string.user_confirm_remove_self_message; - } else if (userInfo.isRestricted()) { - titleResId = R.string.user_profile_confirm_remove_title; - messageResId = R.string.user_profile_confirm_remove_message; - } else if (userInfo.isManagedProfile()) { - titleResId = R.string.work_profile_confirm_remove_title; - messageResId = R.string.work_profile_confirm_remove_message; - } else { - titleResId = R.string.user_confirm_remove_title; - messageResId = R.string.user_confirm_remove_message; - } - Dialog dlg = new AlertDialog.Builder(context) - .setTitle(titleResId) - .setMessage(messageResId) - .setPositiveButton(R.string.user_delete_button, - onConfirmListener) - .setNegativeButton(android.R.string.cancel, null) - .create(); - return dlg; - } /** * Returns whether or not this device is able to be OEM unlocked. @@ -919,7 +884,8 @@ public final class Utils { return CircleFramedDrawable.getInstance(context, icon); } } - return UserIcons.getDefaultUserIcon(user.id, /* light= */ false); + return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap( + UserIcons.getDefaultUserIcon(user.id, /* light= */ false))); } /** @@ -1095,4 +1061,14 @@ public final class Utils { return null; } + public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) { + final TypedArray a = inflater.getContext().obtainStyledAttributes(null, + com.android.internal.R.styleable.Preference, + com.android.internal.R.attr.preferenceCategoryStyle, 0); + final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, + 0); + a.recycle(); + return inflater.inflate(resId, parent, false); + } + } diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java index e9c39d9..0bd6b29 100644 --- a/src/com/android/settings/WirelessSettings.java +++ b/src/com/android/settings/WirelessSettings.java @@ -230,16 +230,6 @@ public class WirelessSettings extends SettingsPreferenceFragment Log.d(TAG, s); } - public static boolean isRadioAllowed(Context context, String type) { - if (!AirplaneModeEnabler.isAirplaneModeOn(context)) { - return true; - } - // Here we use the same logic in onCreate(). - String toggleable = Settings.Global.getString(context.getContentResolver(), - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); - return toggleable != null && toggleable.contains(type); - } - private boolean isSmsSupported() { // Some tablet has sim card but could not do telephony operations. Skip those. return mTm.isSmsCapable(); diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 0b7600b..5fd2e18 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -32,11 +32,13 @@ import android.os.Handler; import android.provider.Settings; import android.text.TextUtils; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.widget.LockPatternUtils; import com.android.settings.ConfirmDeviceCredentialActivity; @@ -168,11 +170,13 @@ public class ToggleAccessibilityServicePreferenceFragment switch (dialogId) { case DIALOG_ID_ENABLE_WARNING: { mShownDialogId = DIALOG_ID_ENABLE_WARNING; - AccessibilityServiceInfo info = getAccessibilityServiceInfo(); + + final AccessibilityServiceInfo info = getAccessibilityServiceInfo(); if (info == null) { return null; } - AlertDialog ad = new AlertDialog.Builder(getActivity()) + + final AlertDialog ad = new AlertDialog.Builder(getActivity()) .setTitle(getString(R.string.enable_service_title, info.getResolveInfo().loadLabel(getPackageManager()))) .setView(createEnableDialogContentView(info)) @@ -180,8 +184,24 @@ public class ToggleAccessibilityServicePreferenceFragment .setPositiveButton(android.R.string.ok, this) .setNegativeButton(android.R.string.cancel, this) .create(); + + final View.OnTouchListener filterTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + // Filter obscured touches by consuming them. + if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { + if (event.getAction() == MotionEvent.ACTION_UP) { + Toast.makeText(v.getContext(), R.string.touch_filtered_warning, + Toast.LENGTH_SHORT).show(); + } + return true; + } + return false; + } + }; + ad.create(); - ad.getButton(AlertDialog.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); + ad.getButton(AlertDialog.BUTTON_POSITIVE).setOnTouchListener(filterTouchListener); return ad; } case DIALOG_ID_DISABLE_WARNING: { diff --git a/src/com/android/settings/accounts/AccountSettings.java b/src/com/android/settings/accounts/AccountSettings.java index ffcb3b8..017eb86 100644 --- a/src/com/android/settings/accounts/AccountSettings.java +++ b/src/com/android/settings/accounts/AccountSettings.java @@ -49,6 +49,7 @@ import android.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; +import com.android.settings.users.UserDialogs; import java.util.ArrayList; import java.util.Collections; @@ -203,7 +204,7 @@ public class AccountSettings extends SettingsPreferenceFragment } if (preference == profileData.removeWorkProfilePreference) { final int userId = profileData.userInfo.id; - Utils.createRemoveConfirmationDialog(getActivity(), userId, + UserDialogs.createRemoveDialog(getActivity(), userId, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java index 858880b..382fa33 100644 --- a/src/com/android/settings/accounts/AccountSyncSettings.java +++ b/src/com/android/settings/accounts/AccountSyncSettings.java @@ -34,7 +34,6 @@ import android.content.SyncAdapterType; import android.content.SyncInfo; import android.content.SyncStatusInfo; import android.content.pm.ProviderInfo; -import android.net.ConnectivityManager; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -440,12 +439,8 @@ public class AccountSyncSettings extends AccountPreferenceBase { !initialSync); syncPref.setFailed(lastSyncFailed); - ConnectivityManager connManager = - (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - final boolean masterSyncAutomatically = - ContentResolver.getMasterSyncAutomaticallyAsUser(userId); - final boolean backgroundDataEnabled = connManager.getBackgroundDataSetting(); - final boolean oneTimeSyncMode = !masterSyncAutomatically || !backgroundDataEnabled; + final boolean oneTimeSyncMode = !ContentResolver.getMasterSyncAutomaticallyAsUser( + userId); syncPref.setOneTimeSyncMode(oneTimeSyncMode); syncPref.setChecked(oneTimeSyncMode || syncEnabled); } diff --git a/src/com/android/settings/applications/ProcStatsEntry.java b/src/com/android/settings/applications/ProcStatsEntry.java index 8702478..6cb6997 100644 --- a/src/com/android/settings/applications/ProcStatsEntry.java +++ b/src/com/android/settings/applications/ProcStatsEntry.java @@ -21,6 +21,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -38,37 +39,49 @@ public final class ProcStatsEntry implements Parcelable { final int mUid; final String mName; final ArrayList<String> mPackages = new ArrayList<String>(); - final long mDuration; - final long mAvgPss; - final long mMaxPss; - final long mAvgUss; - final long mMaxUss; - final long mWeight; + final long mBgDuration; + final long mAvgBgMem; + final long mMaxBgMem; + final double mBgWeight; + final long mRunDuration; + final long mAvgRunMem; + final long mMaxRunMem; + final double mRunWeight; String mBestTargetPackage; ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1); - public ApplicationInfo mUiTargetApp; - public String mUiLabel; - public String mUiBaseLabel; - public String mUiPackage; - public ProcStatsEntry(ProcessStats.ProcessState proc, String packageName, - ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) { - ProcessStats.computeProcessData(proc, tmpTotals, 0); + ProcessStats.ProcessDataCollection tmpBgTotals, + ProcessStats.ProcessDataCollection tmpRunTotals, boolean useUss) { + ProcessStats.computeProcessData(proc, tmpBgTotals, 0); + ProcessStats.computeProcessData(proc, tmpRunTotals, 0); mPackage = proc.mPackage; mUid = proc.mUid; mName = proc.mName; mPackages.add(packageName); - mDuration = tmpTotals.totalTime; - mAvgPss = tmpTotals.avgPss; - mMaxPss = tmpTotals.maxPss; - mAvgUss = tmpTotals.avgUss; - mMaxUss = tmpTotals.maxUss; - mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss); - if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mDuration - + " avgpss=" + mAvgPss + " weight=" + mWeight); + mBgDuration = tmpBgTotals.totalTime; + mAvgBgMem = useUss ? tmpBgTotals.avgUss : tmpBgTotals.avgPss; + mMaxBgMem = useUss ? tmpBgTotals.maxUss : tmpBgTotals.maxPss; + mBgWeight = mAvgBgMem * (double) mBgDuration; + mRunDuration = tmpRunTotals.totalTime; + mAvgRunMem = useUss ? tmpRunTotals.avgUss : tmpRunTotals.avgPss; + mMaxRunMem = useUss ? tmpRunTotals.maxUss : tmpRunTotals.maxPss; + mRunWeight = mAvgRunMem * (double) mRunDuration; + if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mBgDuration + + " avgpss=" + mAvgBgMem + " weight=" + mBgWeight); + } + + public ProcStatsEntry(String pkgName, int uid, String procName, long duration, long mem) { + mPackage = pkgName; + mUid = uid; + mName = procName; + mBgDuration = mRunDuration = duration; + mAvgBgMem = mMaxBgMem = mAvgRunMem = mMaxRunMem = mem; + mBgWeight = mRunWeight = ((double)duration) * mem; + if (DEBUG) Log.d(TAG, "New proc entry " + procName + ": dur=" + mBgDuration + + " avgpss=" + mAvgBgMem + " weight=" + mBgWeight); } public ProcStatsEntry(Parcel in) { @@ -76,12 +89,14 @@ public final class ProcStatsEntry implements Parcelable { mUid = in.readInt(); mName = in.readString(); in.readStringList(mPackages); - mDuration = in.readLong(); - mAvgPss = in.readLong(); - mMaxPss = in.readLong(); - mAvgUss = in.readLong(); - mMaxUss = in.readLong(); - mWeight = in.readLong(); + mBgDuration = in.readLong(); + mAvgBgMem = in.readLong(); + mMaxBgMem = in.readLong(); + mBgWeight = in.readDouble(); + mRunDuration = in.readLong(); + mAvgRunMem = in.readLong(); + mMaxRunMem = in.readLong(); + mRunWeight = in.readDouble(); mBestTargetPackage = in.readString(); final int N = in.readInt(); if (N > 0) { @@ -100,166 +115,139 @@ public final class ProcStatsEntry implements Parcelable { } public void evaluateTargetPackage(PackageManager pm, ProcessStats stats, - ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare, - boolean useUss, boolean weightWithTime) { + ProcessStats.ProcessDataCollection bgTotals, + ProcessStats.ProcessDataCollection runTotals, Comparator<ProcStatsEntry> compare, + boolean useUss) { mBestTargetPackage = null; if (mPackages.size() == 1) { if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0)); mBestTargetPackage = mPackages.get(0); - } else { - // See if there is one significant package that was running here. - ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>(); - for (int ipkg=0; ipkg<mPackages.size(); ipkg++) { - SparseArray<ProcessStats.PackageState> vpkgs - = stats.mPackages.get(mPackages.get(ipkg), mUid); - for (int ivers=0; ivers<vpkgs.size(); ivers++) { - ProcessStats.PackageState pkgState = vpkgs.valueAt(ivers); - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg " - + pkgState + ":"); - if (pkgState == null) { - Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/" - + mUid + " in process " + mName); - continue; - } - ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName); - if (pkgProc == null) { - Log.w(TAG, "No process " + mName + " found in package state " - + mPackages.get(ipkg) + "/" + mUid); - continue; - } - subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, totals, useUss, - weightWithTime)); + return; + } + + // If one of the packages is the framework itself, that wins. + // See if there is one significant package that was running here. + for (int ipkg=0; ipkg<mPackages.size(); ipkg++) { + if ("android".equals(mPackages.get(ipkg))) { + mBestTargetPackage = mPackages.get(ipkg); + return; + } + } + + // Collect information about each package running in the process. + ArrayList<ProcStatsEntry> subProcs = new ArrayList<>(); + for (int ipkg=0; ipkg<mPackages.size(); ipkg++) { + SparseArray<ProcessStats.PackageState> vpkgs + = stats.mPackages.get(mPackages.get(ipkg), mUid); + for (int ivers=0; ivers<vpkgs.size(); ivers++) { + ProcessStats.PackageState pkgState = vpkgs.valueAt(ivers); + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg " + + pkgState + ":"); + if (pkgState == null) { + Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/" + + mUid + " in process " + mName); + continue; + } + ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName); + if (pkgProc == null) { + Log.w(TAG, "No process " + mName + " found in package state " + + mPackages.get(ipkg) + "/" + mUid); + continue; } + subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, bgTotals, + runTotals, useUss)); + } + } + + if (subProcs.size() > 1) { + Collections.sort(subProcs, compare); + if (subProcs.get(0).mRunWeight > (subProcs.get(1).mRunWeight *3)) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg " + + subProcs.get(0).mPackage + " weight " + subProcs.get(0).mRunWeight + + " better than " + subProcs.get(1).mPackage + + " weight " + subProcs.get(1).mRunWeight); + mBestTargetPackage = subProcs.get(0).mPackage; + return; } - if (subProcs.size() > 1) { - Collections.sort(subProcs, compare); - if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) { - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg " - + subProcs.get(0).mPackage + " weight " + subProcs.get(0).mWeight - + " better than " + subProcs.get(1).mPackage - + " weight " + subProcs.get(1).mWeight); - mBestTargetPackage = subProcs.get(0).mPackage; - return; + // Couldn't find one that is best by weight, let's decide on best another + // way: the one that has the longest running service, accounts for at least + // half of the maximum weight, and has specified an explicit app icon. + double maxWeight = subProcs.get(0).mRunWeight; + long bestRunTime = -1; + boolean bestPersistent = false; + for (int i=0; i<subProcs.size(); i++) { + final ProcStatsEntry subProc = subProcs.get(i); + if (subProc.mRunWeight < (maxWeight/2)) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " weight " + subProc.mRunWeight + + " too small"); + continue; } - // Couldn't find one that is best by weight, let's decide on best another - // way: the one that has the longest running service, accounts for at least - // half of the maximum weight, and has specified an explicit app icon. - long maxWeight = subProcs.get(0).mWeight; - long bestRunTime = -1; - for (int i=0; i<subProcs.size(); i++) { - if (subProcs.get(i).mWeight < (maxWeight/2)) { + try { + ApplicationInfo ai = pm.getApplicationInfo(subProc.mPackage, 0); + if (ai.icon == 0) { if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " weight " + subProcs.get(i).mWeight - + " too small"); + + subProc.mPackage + " has no icon"); continue; } - try { - ApplicationInfo ai = pm.getApplicationInfo(subProcs.get(i).mPackage, 0); - if (ai.icon == 0) { + if ((ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0) { + long thisRunTime = subProc.mRunDuration; + if (!bestPersistent || thisRunTime > bestRunTime) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " new best pers run time " + + thisRunTime); + bestRunTime = thisRunTime; + bestPersistent = true; + } else { if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " has no icon"); - continue; + + subProc.mPackage + " pers run time " + thisRunTime + + " not as good as last " + bestRunTime); } - } catch (PackageManager.NameNotFoundException e) { - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " failed finding app info"); continue; - } - ArrayList<Service> subProcServices = null; - for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) { - ArrayList<Service> subServices = mServices.valueAt(isp); - if (subServices.get(0).mPackage.equals(subProcs.get(i).mPackage)) { - subProcServices = subServices; - break; - } - } - long thisRunTime = 0; - if (subProcServices != null) { - for (int iss=0, NSS=subProcServices.size(); iss<NSS; iss++) { - Service service = subProcServices.get(iss); - if (service.mDuration > thisRunTime) { - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " service " + service.mName - + " run time is " + service.mDuration); - thisRunTime = service.mDuration; - break; - } - } - } - if (thisRunTime > bestRunTime) { + } else if (bestPersistent) { if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " new best run time " + thisRunTime); - mBestTargetPackage = subProcs.get(i).mPackage; - bestRunTime = thisRunTime; - } else { - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " run time " + thisRunTime - + " not as good as last " + bestRunTime); + + subProc.mPackage + " is not persistent"); + continue; } + } catch (PackageManager.NameNotFoundException e) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " failed finding app info"); + continue; } - } else if (subProcs.size() == 1) { - mBestTargetPackage = subProcs.get(0).mPackage; - } - } - } - - public void retrieveUiData(PackageManager pm) { - mUiTargetApp = null; - mUiLabel = mUiBaseLabel = mName; - mUiPackage = mBestTargetPackage; - if (mUiPackage != null) { - // Only one app associated with this process. - try { - mUiTargetApp = pm.getApplicationInfo(mUiPackage, - PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.GET_UNINSTALLED_PACKAGES); - String name = mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString(); - if (mName.equals(mUiPackage)) { - mUiLabel = name; - } else { - if (mName.startsWith(mUiPackage)) { - int off = mUiPackage.length(); - if (mName.length() > off) { - off++; - } - mUiLabel = name + " (" + mName.substring(off) + ")"; - } else { - mUiLabel = name + " (" + mName + ")"; + ArrayList<Service> subProcServices = null; + for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) { + ArrayList<Service> subServices = mServices.valueAt(isp); + if (subServices.get(0).mPackage.equals(subProc.mPackage)) { + subProcServices = subServices; + break; } } - } catch (PackageManager.NameNotFoundException e) { - } - } - if (mUiTargetApp == null) { - String[] packages = pm.getPackagesForUid(mUid); - if (packages != null) { - for (String curPkg : packages) { - try { - final PackageInfo pi = pm.getPackageInfo(curPkg, - PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.GET_UNINSTALLED_PACKAGES); - if (pi.sharedUserLabel != 0) { - mUiTargetApp = pi.applicationInfo; - final CharSequence nm = pm.getText(curPkg, - pi.sharedUserLabel, pi.applicationInfo); - if (nm != null) { - mUiBaseLabel = nm.toString(); - mUiLabel = mUiBaseLabel + " (" + mName + ")"; - } else { - mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString(); - mUiLabel = mUiBaseLabel + " (" + mName + ")"; - } + long thisRunTime = 0; + if (subProcServices != null) { + for (int iss=0, NSS=subProcServices.size(); iss<NSS; iss++) { + Service service = subProcServices.get(iss); + if (service.mDuration > thisRunTime) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " service " + service.mName + + " run time is " + service.mDuration); + thisRunTime = service.mDuration; break; } - } catch (PackageManager.NameNotFoundException e) { } } - } else { - // no current packages for this uid, typically because of uninstall - Log.i(TAG, "No package for uid " + mUid); + if (thisRunTime > bestRunTime) { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " new best run time " + thisRunTime); + mBestTargetPackage = subProc.mPackage; + bestRunTime = thisRunTime; + } else { + if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " + + subProc.mPackage + " run time " + thisRunTime + + " not as good as last " + bestRunTime); + } } + } else if (subProcs.size() == 1) { + mBestTargetPackage = subProcs.get(0).mPackage; } } @@ -283,12 +271,14 @@ public final class ProcStatsEntry implements Parcelable { dest.writeInt(mUid); dest.writeString(mName); dest.writeStringList(mPackages); - dest.writeLong(mDuration); - dest.writeLong(mAvgPss); - dest.writeLong(mMaxPss); - dest.writeLong(mAvgUss); - dest.writeLong(mMaxUss); - dest.writeLong(mWeight); + dest.writeLong(mBgDuration); + dest.writeLong(mAvgBgMem); + dest.writeLong(mMaxBgMem); + dest.writeDouble(mBgWeight); + dest.writeLong(mRunDuration); + dest.writeLong(mAvgRunMem); + dest.writeLong(mMaxRunMem); + dest.writeDouble(mRunWeight); dest.writeString(mBestTargetPackage); final int N = mServices.size(); dest.writeInt(N); diff --git a/src/com/android/settings/applications/ProcStatsPackageEntry.java b/src/com/android/settings/applications/ProcStatsPackageEntry.java new file mode 100644 index 0000000..3925d1d --- /dev/null +++ b/src/com/android/settings/applications/ProcStatsPackageEntry.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 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 com.android.settings.applications; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.settings.R; + +import java.util.ArrayList; + +public class ProcStatsPackageEntry implements Parcelable { + private static final String TAG = "ProcStatsEntry"; + private static boolean DEBUG = ProcessStatsUi.DEBUG; + + final String mPackage; + final ArrayList<ProcStatsEntry> mEntries = new ArrayList<ProcStatsEntry>(); + + long mBgDuration; + long mAvgBgMem; + long mMaxBgMem; + double mBgWeight; + long mRunDuration; + long mAvgRunMem; + long mMaxRunMem; + double mRunWeight; + + public ApplicationInfo mUiTargetApp; + public String mUiLabel; + + public ProcStatsPackageEntry(String pkg) { + mPackage = pkg; + } + + public ProcStatsPackageEntry(Parcel in) { + mPackage = in.readString(); + in.readTypedList(mEntries, ProcStatsEntry.CREATOR); + mBgDuration = in.readLong(); + mAvgBgMem = in.readLong(); + mMaxBgMem = in.readLong(); + mBgWeight = in.readDouble(); + mRunDuration = in.readLong(); + mAvgRunMem = in.readLong(); + mMaxRunMem = in.readLong(); + mRunWeight = in.readDouble(); + } + + public void addEntry(ProcStatsEntry entry) { + mEntries.add(entry); + } + + public void updateMetrics() { + mBgDuration = mAvgBgMem = mMaxBgMem = 0; + mBgWeight = 0; + mRunDuration = mAvgRunMem = mMaxRunMem = 0; + mRunWeight = 0; + final int N = mEntries.size(); + for (int i=0; i<N; i++) { + ProcStatsEntry entry = mEntries.get(i); + mBgDuration += entry.mBgDuration; + mAvgBgMem += entry.mAvgBgMem; + if (entry.mMaxBgMem > mMaxBgMem) { + mMaxBgMem = entry.mMaxBgMem; + } + mBgWeight += entry.mBgWeight; + mRunDuration += entry.mRunDuration; + mAvgRunMem += entry.mAvgRunMem; + if (entry.mMaxRunMem > mMaxRunMem) { + mMaxRunMem = entry.mMaxRunMem; + } + mRunWeight += entry.mRunWeight; + } + mAvgBgMem /= N; + mAvgRunMem /= N; + } + + public void retrieveUiData(Context context, PackageManager pm) { + mUiTargetApp = null; + mUiLabel = mPackage; + // Only one app associated with this process. + try { + if ("os".equals(mPackage)) { + mUiTargetApp = pm.getApplicationInfo("android", + PackageManager.GET_DISABLED_COMPONENTS | + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | + PackageManager.GET_UNINSTALLED_PACKAGES); + mUiLabel = context.getString(R.string.process_stats_os_label); + } else { + mUiTargetApp = pm.getApplicationInfo(mPackage, + PackageManager.GET_DISABLED_COMPONENTS | + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | + PackageManager.GET_UNINSTALLED_PACKAGES); + mUiLabel = mUiTargetApp.loadLabel(pm).toString(); + } + } catch (PackageManager.NameNotFoundException e) { + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPackage); + dest.writeTypedList(mEntries); + dest.writeLong(mBgDuration); + dest.writeLong(mAvgBgMem); + dest.writeLong(mMaxBgMem); + dest.writeDouble(mBgWeight); + dest.writeLong(mRunDuration); + dest.writeLong(mAvgRunMem); + dest.writeLong(mMaxRunMem); + dest.writeDouble(mRunWeight); + } + + public static final Parcelable.Creator<ProcStatsPackageEntry> CREATOR + = new Parcelable.Creator<ProcStatsPackageEntry>() { + public ProcStatsPackageEntry createFromParcel(Parcel in) { + return new ProcStatsPackageEntry(in); + } + + public ProcStatsPackageEntry[] newArray(int size) { + return new ProcStatsPackageEntry[size]; + } + }; +} diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java index 30f6b52..f0e76d4 100644 --- a/src/com/android/settings/applications/ProcessStatsDetail.java +++ b/src/com/android/settings/applications/ProcessStatsDetail.java @@ -16,20 +16,14 @@ package com.android.settings.applications; -import android.app.Activity; import android.app.ActivityManager; import android.app.Fragment; import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.net.Uri; import android.os.Bundle; import android.os.Process; -import android.os.UserHandle; import android.text.format.Formatter; import android.view.LayoutInflater; import android.view.View; @@ -44,6 +38,7 @@ import com.android.settings.Utils; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import static com.android.settings.Utils.prepareCustomPreferencesList; @@ -52,25 +47,28 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen public static final int ACTION_FORCE_STOP = 1; - public static final String EXTRA_ENTRY = "entry"; + public static final String EXTRA_PACKAGE_ENTRY = "package_entry"; public static final String EXTRA_USE_USS = "use_uss"; public static final String EXTRA_MAX_WEIGHT = "max_weight"; + public static final String EXTRA_WEIGHT_TO_RAM = "weight_to_ram"; public static final String EXTRA_TOTAL_TIME = "total_time"; private PackageManager mPm; private DevicePolicyManager mDpm; - private ProcStatsEntry mEntry; + private ProcStatsPackageEntry mApp; private boolean mUseUss; - private long mMaxWeight; + private double mMaxWeight; + private double mWeightToRam; private long mTotalTime; + private long mOnePercentTime; private View mRootView; private TextView mTitleView; private ViewGroup mTwoButtonsPanel; private Button mForceStopButton; private Button mReportButton; - private ViewGroup mDetailsParent; + private ViewGroup mProcessesParent; private ViewGroup mServicesParent; @Override @@ -79,11 +77,13 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen mPm = getActivity().getPackageManager(); mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); final Bundle args = getArguments(); - mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY); - mEntry.retrieveUiData(mPm); + mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY); + mApp.retrieveUiData(getActivity(), mPm); mUseUss = args.getBoolean(EXTRA_USE_USS); - mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT); + mMaxWeight = args.getDouble(EXTRA_MAX_WEIGHT); + mWeightToRam = args.getDouble(EXTRA_WEIGHT_TO_RAM); mTotalTime = args.getLong(EXTRA_TOTAL_TIME); + mOnePercentTime = mTotalTime/100; } @Override @@ -109,24 +109,22 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen } private void createDetails() { - final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100; + final double percentOfWeight = (mApp.mBgWeight / mMaxWeight) * 100; int appLevel = (int) Math.ceil(percentOfWeight); - String appLevelText = Utils.formatPercentage(mEntry.mDuration, mTotalTime); + String appLevelText = Formatter.formatShortFileSize(getActivity(), + (long)(mApp.mRunWeight * mWeightToRam)); // Set all values in the header. - final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary); - summary.setText(mEntry.mName); - summary.setVisibility(View.VISIBLE); mTitleView = (TextView) mRootView.findViewById(android.R.id.title); - mTitleView.setText(mEntry.mUiBaseLabel); + mTitleView.setText(mApp.mUiLabel); final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1); text1.setText(appLevelText); final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress); progress.setProgress(appLevel); final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon); - if (mEntry.mUiTargetApp != null) { - icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm)); + if (mApp.mUiTargetApp != null) { + icon.setImageDrawable(mApp.mUiTargetApp.loadIcon(mPm)); } mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel); @@ -135,13 +133,17 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen mForceStopButton.setEnabled(false); mReportButton.setVisibility(View.INVISIBLE); - mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details); + mProcessesParent = (ViewGroup)mRootView.findViewById(R.id.processes); mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services); - fillDetailsSection(); + fillProcessesSection(); fillServicesSection(); + if (mServicesParent.getChildCount() <= 0) { + mServicesParent.setVisibility(View.GONE); + mRootView.findViewById(R.id.services_label).setVisibility(View.GONE); + } - if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) { + if (mApp.mEntries.get(0).mUid >= android.os.Process.FIRST_APPLICATION_UID) { mForceStopButton.setText(R.string.force_stop); mForceStopButton.setTag(ACTION_FORCE_STOP); mForceStopButton.setOnClickListener(this); @@ -191,15 +193,43 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen valueView.setText(value); } - private void fillDetailsSection() { - addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_avg_ram_use), - Formatter.formatShortFileSize(getActivity(), - (mUseUss ? mEntry.mAvgUss : mEntry.mAvgPss) * 1024)); - addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_max_ram_use), - Formatter.formatShortFileSize(getActivity(), - (mUseUss ? mEntry.mMaxUss : mEntry.mMaxPss) * 1024)); - addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time), - Utils.formatPercentage(mEntry.mDuration, mTotalTime)); + final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() { + @Override + public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) { + if (lhs.mRunWeight < rhs.mRunWeight) { + return 1; + } else if (lhs.mRunWeight > rhs.mRunWeight) { + return -1; + } + return 0; + } + }; + + private void fillProcessesSection() { + final ArrayList<ProcStatsEntry> entries = new ArrayList<>(); + for (int ie=0; ie<mApp.mEntries.size(); ie++) { + ProcStatsEntry entry = mApp.mEntries.get(ie); + entries.add(entry); + } + Collections.sort(entries, sEntryCompare); + for (int ie=0; ie<entries.size(); ie++) { + ProcStatsEntry entry = entries.get(ie); + LayoutInflater inflater = getActivity().getLayoutInflater(); + ViewGroup item = (ViewGroup) inflater.inflate(R.layout.process_stats_proc_details, + null); + mProcessesParent.addView(item); + ((TextView)item.findViewById(R.id.processes_name)).setText(entry.mName); + addDetailsItem(item, getResources().getText(R.string.process_stats_ram_use), + Formatter.formatShortFileSize(getActivity(), + (long)(entry.mRunWeight * mWeightToRam))); + if (entry.mBgWeight > 0) { + addDetailsItem(item, getResources().getText(R.string.process_stats_bg_ram_use), + Formatter.formatShortFileSize(getActivity(), + (long)(entry.mBgWeight * mWeightToRam))); + } + addDetailsItem(item, getResources().getText(R.string.process_stats_run_time), + Utils.formatPercentage(entry.mRunDuration, mTotalTime)); + } } final static Comparator<ProcStatsEntry.Service> sServiceCompare @@ -215,55 +245,65 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen } }; - final static Comparator<ArrayList<ProcStatsEntry.Service>> sServicePkgCompare - = new Comparator<ArrayList<ProcStatsEntry.Service>>() { + final static Comparator<PkgService> sServicePkgCompare = new Comparator<PkgService>() { @Override - public int compare(ArrayList<ProcStatsEntry.Service> lhs, - ArrayList<ProcStatsEntry.Service> rhs) { - long topLhs = lhs.size() > 0 ? lhs.get(0).mDuration : 0; - long topRhs = rhs.size() > 0 ? rhs.get(0).mDuration : 0; - if (topLhs < topRhs) { + public int compare(PkgService lhs, PkgService rhs) { + if (lhs.mDuration < rhs.mDuration) { return 1; - } else if (topLhs > topRhs) { + } else if (lhs.mDuration > rhs.mDuration) { return -1; } return 0; } }; + static class PkgService { + final ArrayList<ProcStatsEntry.Service> mServices = new ArrayList<>(); + long mDuration; + } + private void fillServicesSection() { - if (mEntry.mServices.size() > 0) { - boolean addPackageSections = false; - // Sort it all. - ArrayList<ArrayList<ProcStatsEntry.Service>> servicePkgs - = new ArrayList<ArrayList<ProcStatsEntry.Service>>(); - for (int ip=0; ip<mEntry.mServices.size(); ip++) { - ArrayList<ProcStatsEntry.Service> services = - (ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone(); - Collections.sort(services, sServiceCompare); - servicePkgs.add(services); + final HashMap<String, PkgService> pkgServices = new HashMap<>(); + final ArrayList<PkgService> pkgList = new ArrayList<>(); + for (int ie=0; ie< mApp.mEntries.size(); ie++) { + ProcStatsEntry ent = mApp.mEntries.get(ie); + for (int ip=0; ip<ent.mServices.size(); ip++) { + String pkg = ent.mServices.keyAt(ip); + PkgService psvc = null; + ArrayList<ProcStatsEntry.Service> services = ent.mServices.valueAt(ip); + for (int is=services.size()-1; is>=0; is--) { + ProcStatsEntry.Service pent = services.get(is); + if (pent.mDuration >= mOnePercentTime) { + if (psvc == null) { + psvc = pkgServices.get(pkg); + if (psvc == null) { + psvc = new PkgService(); + pkgServices.put(pkg, psvc); + pkgList.add(psvc); + } + } + psvc.mServices.add(pent); + psvc.mDuration += pent.mDuration; + } + } } - if (mEntry.mServices.size() > 1 - || !mEntry.mServices.valueAt(0).get(0).mPackage.equals(mEntry.mPackage)) { - addPackageSections = true; - // Sort these so that the one(s) with the longest run durations are on top. - Collections.sort(servicePkgs, sServicePkgCompare); + } + Collections.sort(pkgList, sServicePkgCompare); + for (int ip=0; ip<pkgList.size(); ip++) { + ArrayList<ProcStatsEntry.Service> services = pkgList.get(ip).mServices; + Collections.sort(services, sServiceCompare); + if (pkgList.size() > 1) { + addPackageHeaderItem(mServicesParent, services.get(0).mPackage); } - for (int ip=0; ip<servicePkgs.size(); ip++) { - ArrayList<ProcStatsEntry.Service> services = servicePkgs.get(ip); - if (addPackageSections) { - addPackageHeaderItem(mServicesParent, services.get(0).mPackage); - } - for (int is=0; is<services.size(); is++) { - ProcStatsEntry.Service service = services.get(is); - String label = service.mName; - int tail = label.lastIndexOf('.'); - if (tail >= 0 && tail < (label.length()-1)) { - label = label.substring(tail+1); - } - String percentage = Utils.formatPercentage(service.mDuration, mTotalTime); - addDetailsItem(mServicesParent, label, percentage); + for (int is=0; is<services.size(); is++) { + ProcStatsEntry.Service service = services.get(is); + String label = service.mName; + int tail = label.lastIndexOf('.'); + if (tail >= 0 && tail < (label.length()-1)) { + label = label.substring(tail+1); } + String percentage = Utils.formatPercentage(service.mDuration, mTotalTime); + addDetailsItem(mServicesParent, label, percentage); } } } @@ -271,39 +311,40 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen private void killProcesses() { ActivityManager am = (ActivityManager)getActivity().getSystemService( Context.ACTIVITY_SERVICE); - am.forceStopPackage(mEntry.mUiPackage); + for (int i=0; i< mApp.mEntries.size(); i++) { + ProcStatsEntry ent = mApp.mEntries.get(i); + for (int j=0; j<ent.mPackages.size(); j++) { + am.forceStopPackage(ent.mPackages.get(j)); + } + } checkForceStop(); } - private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); - } - }; - private void checkForceStop() { - if (mEntry.mUiPackage == null || mEntry.mUid < Process.FIRST_APPLICATION_UID) { + if (mApp.mEntries.get(0).mUid < Process.FIRST_APPLICATION_UID) { mForceStopButton.setEnabled(false); return; } - if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) { - mForceStopButton.setEnabled(false); - return; - } - try { - ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0); - if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { - mForceStopButton.setEnabled(true); + boolean isStarted = false; + for (int i=0; i< mApp.mEntries.size(); i++) { + ProcStatsEntry ent = mApp.mEntries.get(i); + for (int j=0; j<ent.mPackages.size(); j++) { + String pkg = ent.mPackages.get(j); + if (mDpm.packageHasActiveAdmins(pkg)) { + mForceStopButton.setEnabled(false); + return; + } + try { + ApplicationInfo info = mPm.getApplicationInfo(pkg, 0); + if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { + isStarted = true; + } + } catch (PackageManager.NameNotFoundException e) { + } } - } catch (PackageManager.NameNotFoundException e) { } - Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, - Uri.fromParts("package", mEntry.mUiPackage, null)); - intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mEntry.mUiPackage }); - intent.putExtra(Intent.EXTRA_UID, mEntry.mUid); - intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mEntry.mUid)); - getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, - Activity.RESULT_CANCELED, null, null); + if (isStarted) { + mForceStopButton.setEnabled(true); + } } } diff --git a/src/com/android/settings/applications/ProcessStatsPreference.java b/src/com/android/settings/applications/ProcessStatsPreference.java index adf80e5..a0839d3 100644 --- a/src/com/android/settings/applications/ProcessStatsPreference.java +++ b/src/com/android/settings/applications/ProcessStatsPreference.java @@ -29,7 +29,7 @@ import com.android.settings.R; import com.android.settings.Utils; public class ProcessStatsPreference extends Preference { - private ProcStatsEntry mEntry; + private ProcStatsPackageEntry mEntry; private int mProgress; private CharSequence mProgressText; @@ -51,18 +51,19 @@ public class ProcessStatsPreference extends Preference { setLayoutResource(R.layout.preference_app_percentage); } - public void init(Drawable icon, ProcStatsEntry entry) { + public void init(Drawable icon, ProcStatsPackageEntry entry) { mEntry = entry; setIcon(icon != null ? icon : new ColorDrawable(0)); } - public ProcStatsEntry getEntry() { + public ProcStatsPackageEntry getEntry() { return mEntry; } - public void setPercent(double percentOfWeight, double percentOfTime) { + public void setPercent(double percentOfWeight, double percentOfTime, long memory) { mProgress = (int) Math.ceil(percentOfWeight); - mProgressText = Utils.formatPercentage((int) percentOfTime); + //mProgressText = Utils.formatPercentage((int) percentOfTime); + mProgressText = Formatter.formatShortFileSize(getContext(), memory); notifyChanged(); } diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java index 30a8817..14e0b90 100644 --- a/src/com/android/settings/applications/ProcessStatsUi.java +++ b/src/com/android/settings/applications/ProcessStatsUi.java @@ -19,6 +19,7 @@ package com.android.settings.applications; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -50,6 +51,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; public class ProcessStatsUi extends PreferenceFragment implements LinearColorBar.OnRegionTappedListener { @@ -75,13 +77,30 @@ public class ProcessStatsUi extends PreferenceFragment final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() { @Override public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) { - if (lhs.mWeight < rhs.mWeight) { + if (lhs.mRunWeight < rhs.mRunWeight) { return 1; - } else if (lhs.mWeight > rhs.mWeight) { + } else if (lhs.mRunWeight > rhs.mRunWeight) { return -1; - } else if (lhs.mDuration < rhs.mDuration) { + } else if (lhs.mRunDuration < rhs.mRunDuration) { return 1; - } else if (lhs.mDuration > rhs.mDuration) { + } else if (lhs.mRunDuration > rhs.mRunDuration) { + return -1; + } + return 0; + } + }; + + final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare + = new Comparator<ProcStatsPackageEntry>() { + @Override + public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { + if (lhs.mRunWeight < rhs.mRunWeight) { + return 1; + } else if (lhs.mRunWeight > rhs.mRunWeight) { + return -1; + } else if (lhs.mRunDuration < rhs.mRunDuration) { + return 1; + } else if (lhs.mRunDuration > rhs.mRunDuration) { return -1; } return 0; @@ -112,7 +131,7 @@ public class ProcessStatsUi extends PreferenceFragment private PreferenceGroup mAppListGroup; private Preference mMemStatusPref; - long mMaxWeight; + double mMaxWeight; long mTotalTime; long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT]; @@ -123,6 +142,7 @@ public class ProcessStatsUi extends PreferenceFragment double mMemKernelWeight; double mMemNativeWeight; double mMemTotalWeight; + double mWeightToRam; // The actual duration value to use for each duration option. Note these // are lower than the actual duration, since our durations are computed in @@ -218,9 +238,10 @@ public class ProcessStatsUi extends PreferenceFragment ProcessStatsPreference pgp = (ProcessStatsPreference) preference; Bundle args = new Bundle(); - args.putParcelable(ProcessStatsDetail.EXTRA_ENTRY, pgp.getEntry()); + args.putParcelable(ProcessStatsDetail.EXTRA_PACKAGE_ENTRY, pgp.getEntry()); args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss); - args.putLong(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight); + args.putDouble(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight); + args.putDouble(ProcessStatsDetail.EXTRA_WEIGHT_TO_RAM, mWeightToRam); args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime); ((SettingsActivity) getActivity()).startPreferencePanel( ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0); @@ -349,11 +370,19 @@ public class ProcessStatsUi extends PreferenceFragment mAppListGroup.addPreference(notAvailable); } + /** + * All states in which we consider a process to be actively running (rather than + * something that can be freely killed to reclaim RAM). Note this also includes + * the HOME state, because we prioritize home over all cached processes even when + * it is in the background, so it is effectively always running from the perspective + * of the information we want to show the user here. + */ public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] { ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND, ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP, ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE, - ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER + ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER, + ProcessStats.STATE_HOME }; public static final int[] FOREGROUND_PROC_STATES = new int[] { @@ -406,31 +435,6 @@ public class ProcessStatsUi extends PreferenceFragment final long elapsedTime = mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime; - mMemStatusPref.setOrder(-2); - mAppListGroup.addPreference(mMemStatusPref); - String durationString = Utils.formatElapsedTime(getActivity(), elapsedTime, false); - CharSequence memString; - CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states); - if (mMemState >= 0 && mMemState < memStatesStr.length) { - memString = memStatesStr[mMemState]; - } else { - memString = "?"; - } - mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration, - getActivity().getString(statsLabel), durationString)); - mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status, - memString)); - /* - mMemStatusPref.setTitle(DateFormat.format(DateFormat.getBestDateTimePattern( - getActivity().getResources().getConfiguration().locale, - "MMMM dd, yyyy h:mm a"), mStats.mTimePeriodStartClock)); - */ - /* - BatteryHistoryPreference hist = new BatteryHistoryPreference(getActivity(), mStats); - hist.setOrder(-1); - mAppListGroup.addPreference(hist); - */ - long now = SystemClock.uptimeMillis(); final PackageManager pm = getActivity().getPackageManager(); @@ -470,9 +474,13 @@ public class ProcessStatsUi extends PreferenceFragment memStates = ProcessStats.ALL_MEM_ADJ; break; } - colors.setColoredRegions(LinearColorBar.REGION_RED); + Resources res = getResources(); + colors.setColors(res.getColor(R.color.running_processes_apps_ram), + res.getColor(R.color.running_processes_apps_ram), + res.getColor(R.color.running_processes_free_ram)); // Compute memory badness for chart color. + /* int[] badColors = com.android.settings.Utils.BADNESS_COLORS; long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL]; timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3; @@ -480,6 +488,7 @@ public class ProcessStatsUi extends PreferenceFragment float memBadness = ((float)timeGood)/mTotalTime; int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))]; colors.setColors(badnessColor, badnessColor, badnessColor); + */ // We are now going to scale the mMemTimes to match the total elapsed time. // These are in uptime, so they will often be smaller than the elapsed time, @@ -547,6 +556,8 @@ public class ProcessStatsUi extends PreferenceFragment memReader.readMemInfo(); double realTotalRam = memReader.getTotalSize(); double totalScale = realTotalRam / totalRam; + mWeightToRam = totalScale / memTotalTime * 1024; + mMaxWeight = totalRam / mWeightToRam; double realUsedRam = usedRam * totalScale; double realFreeRam = freeRam * totalScale; if (DEBUG) { @@ -558,12 +569,15 @@ public class ProcessStatsUi extends PreferenceFragment ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); ((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo( memInfo); + long baseCacheRam; if (memInfo.hiddenAppThreshold >= realFreeRam) { realUsedRam = realFreeRam; realFreeRam = 0; + baseCacheRam = (long)realFreeRam; } else { realUsedRam += memInfo.hiddenAppThreshold; realFreeRam -= memInfo.hiddenAppThreshold; + baseCacheRam = memInfo.hiddenAppThreshold; } if (DEBUG) { Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(), @@ -572,6 +586,22 @@ public class ProcessStatsUi extends PreferenceFragment (long)realFreeRam)); } + mMemStatusPref.setOrder(-2); + mAppListGroup.addPreference(mMemStatusPref); + String durationString = Utils.formatElapsedTime(getActivity(), elapsedTime, false); + String usedString = Formatter.formatShortFileSize(getActivity(), (long) realUsedRam); + String totalString = Formatter.formatShortFileSize(getActivity(), (long)realTotalRam); + CharSequence memString; + CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states); + if (mMemState >= 0 && mMemState < memStatesStr.length) { + memString = memStatesStr[mMemState]; + } else { + memString = "?"; + } + mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration, + usedString, totalString, durationString)); + mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status, + memString)); float usedRatio = (float)(realUsedRam/(realFreeRam+realUsedRam)); colors.setRatios(usedRatio, 0, 1-usedRatio); @@ -605,17 +635,20 @@ public class ProcessStatsUi extends PreferenceFragment mAppListGroup.addPreference(colors); - ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection( + ProcessStats.ProcessDataCollection bgTotals = new ProcessStats.ProcessDataCollection( ProcessStats.ALL_SCREEN_ADJ, memStates, stats); + ProcessStats.ProcessDataCollection runTotals = new ProcessStats.ProcessDataCollection( + ProcessStats.ALL_SCREEN_ADJ, memStates, ProcessStats.NON_CACHED_PROC_STATES); - ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>(); + final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>(); + final ArrayList<ProcStatsPackageEntry> pkgEntries = new ArrayList<>(); /* ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked( ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ, ProcessStats.BACKGROUND_PROC_STATES, now, null); for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) { - procs.add(new ProcStatsEntry(rawProcs.get(i), totals)); + procs.add(new ProcStatsEntry(rawProcs.get(i), bgTotals)); } */ @@ -640,15 +673,15 @@ public class ProcessStatsUi extends PreferenceFragment } ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid); if (ent == null) { - ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss, - mStatsType == MENU_TYPE_BACKGROUND); - if (ent.mDuration > 0) { + ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals, + mUseUss); + if (ent.mRunWeight > 0) { if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/" - + proc.mUid + ": time=" + makeDuration(ent.mDuration) + " (" - + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)" - + " pss=" + ent.mAvgPss); + + proc.mUid + ": time=" + makeDuration(ent.mRunDuration) + " (" + + ((((double)ent.mRunDuration) / memTotalTime) * 100) + "%)" + + " pss=" + ent.mAvgRunMem); entriesMap.put(proc.mName, proc.mUid, ent); - entries.add(ent); + procEntries.add(ent); } } else { ent.addPackage(st.mPackageName); @@ -672,7 +705,8 @@ public class ProcessStatsUi extends PreferenceFragment for (int is=0, NS=ps.mServices.size(); is<NS; is++) { ProcessStats.ServiceState ss = ps.mServices.valueAt(is); if (ss.mProcessName != null) { - ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu)); + ProcStatsEntry ent = entriesMap.get(ss.mProcessName, + uids.keyAt(iu)); if (ent != null) { if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName + "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc " @@ -689,90 +723,99 @@ public class ProcessStatsUi extends PreferenceFragment } } - /* - SparseArray<ArrayMap<String, ProcStatsEntry>> processes - = new SparseArray<ArrayMap<String, ProcStatsEntry>>(); - for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) { - SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip); - for (int iu=0; iu<uids.size(); iu++) { - ProcessStats.ProcessState st = uids.valueAt(iu); - ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss, - mStatsType == MENU_TYPE_BACKGROUND); - if (ent.mDuration > 0) { - if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time=" - + makeDuration(ent.mDuration) + " (" - + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"); - procs.add(ent); - ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid); - if (uidProcs == null) { - uidProcs = new ArrayMap<String, ProcStatsEntry>(); - processes.put(ent.mUid, uidProcs); - } - uidProcs.put(ent.mName, ent); - } + // Combine processes into packages. + HashMap<String, ProcStatsPackageEntry> pkgMap = new HashMap<>(); + for (int i=procEntries.size()-1; i>=0; i--) { + ProcStatsEntry proc = procEntries.get(i); + proc.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); + ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage); + if (pkg == null) { + pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage); + pkgMap.put(proc.mBestTargetPackage, pkg); + pkgEntries.add(pkg); } + pkg.addEntry(proc); } - */ - Collections.sort(entries, sEntryCompare); - - long maxWeight = 1; - for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) { - ProcStatsEntry proc = entries.get(i); - if (maxWeight < proc.mWeight) { - maxWeight = proc.mWeight; - } + // Add in fake entry representing the OS itself. + ProcStatsPackageEntry osPkg = new ProcStatsPackageEntry("os"); + pkgMap.put("os", osPkg); + pkgEntries.add(osPkg); + ProcStatsEntry osEntry; + if (totalMem.sysMemNativeWeight > 0) { + osEntry = new ProcStatsEntry("os", 0, + getString(R.string.process_stats_os_native), memTotalTime, + (long)(totalMem.sysMemNativeWeight/memTotalTime)); + osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); + osPkg.addEntry(osEntry); } - if (mStatsType == MENU_TYPE_BACKGROUND) { - mMaxWeight = (long)(mShowSystem ? persBackgroundWeight : backgroundWeight); - if (mMaxWeight < maxWeight) { - mMaxWeight = maxWeight; - } - if (DEBUG) { - Log.i(TAG, "Bar max RAM: " + Formatter.formatShortFileSize(getActivity(), - (mMaxWeight * 1024) / memTotalTime)); - } - } else { - mMaxWeight = maxWeight; + if (totalMem.sysMemKernelWeight > 0) { + osEntry = new ProcStatsEntry("os", 0, + getString(R.string.process_stats_os_kernel), memTotalTime, + (long)(totalMem.sysMemKernelWeight/memTotalTime)); + osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); + osPkg.addEntry(osEntry); + } + if (totalMem.sysMemZRamWeight > 0) { + osEntry = new ProcStatsEntry("os", 0, + getString(R.string.process_stats_os_zram), memTotalTime, + (long)(totalMem.sysMemZRamWeight/memTotalTime)); + osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); + osPkg.addEntry(osEntry); } + if (baseCacheRam > 0) { + osEntry = new ProcStatsEntry("os", 0, + getString(R.string.process_stats_os_cache), memTotalTime, baseCacheRam/1024); + osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); + osPkg.addEntry(osEntry); + } + + for (int i=0, N=pkgEntries.size(); i<N; i++) { + ProcStatsPackageEntry pkg = pkgEntries.get(i); + pkg.updateMetrics(); + } + + Collections.sort(pkgEntries, sPackageEntryCompare); + + // Now collect the per-process information into applications, so that applications + // running as multiple processes will have only one entry representing all of them. if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); // Find where we should stop. Because we have two properties we are looking at, // we need to go from the back looking for the first place either holds. - int end = entries != null ? entries.size()-1 : -1; + int end = pkgEntries.size()-1; while (end >= 0) { - ProcStatsEntry proc = entries.get(end); - final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100; - final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100; - if (percentOfWeight >= 1 || percentOfTime >= 25) { + ProcStatsPackageEntry pkg = pkgEntries.get(end); + final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100; + final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100; + if (percentOfWeight >= .01 || percentOfTime >= 25) { break; } end--; } for (int i=0; i<=end; i++) { - ProcStatsEntry proc = entries.get(i); - final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100; - final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100; + ProcStatsPackageEntry pkg = pkgEntries.get(i); + final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100; + final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100; ProcessStatsPreference pref = new ProcessStatsPreference(getActivity()); - pref.init(null, proc); - proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss, - mStatsType == MENU_TYPE_BACKGROUND); - proc.retrieveUiData(pm); - pref.setTitle(proc.mUiLabel); - if (proc.mUiTargetApp != null) { - pref.setIcon(proc.mUiTargetApp.loadIcon(pm)); + pref.init(null, pkg); + pkg.retrieveUiData(getActivity(), pm); + pref.setTitle(pkg.mUiLabel); + if (pkg.mUiTargetApp != null) { + pref.setIcon(pkg.mUiTargetApp.loadIcon(pm)); } pref.setOrder(i); - pref.setPercent(percentOfWeight, percentOfTime); + pref.setPercent(percentOfWeight, percentOfTime, + (long)(pkg.mRunWeight * mWeightToRam)); mAppListGroup.addPreference(pref); if (mStatsType == MENU_TYPE_BACKGROUND) { if (DEBUG) { - Log.i(TAG, "App " + proc.mUiLabel + ": weightedRam=" + Log.i(TAG, "App " + pkg.mUiLabel + ": weightedRam=" + Formatter.formatShortFileSize(getActivity(), - (proc.mWeight * 1024) / memTotalTime) + (long)((pkg.mRunWeight * 1024) / memTotalTime)) + ", avgRam=" + Formatter.formatShortFileSize(getActivity(), - (proc.mAvgPss*1024))); + (pkg.mAvgRunMem *1024))); } } diff --git a/src/com/android/settings/applications/RunningState.java b/src/com/android/settings/applications/RunningState.java index 4b58729..f0c33dd 100644 --- a/src/com/android/settings/applications/RunningState.java +++ b/src/com/android/settings/applications/RunningState.java @@ -19,8 +19,11 @@ package com.android.settings.applications; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageItemInfo; @@ -28,8 +31,6 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.ConstantState; import android.os.Handler; @@ -45,7 +46,6 @@ import android.util.SparseArray; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.drawable.CircleFramedDrawable; import java.util.ArrayList; import java.util.Collections; @@ -124,9 +124,6 @@ public class RunningState { // representing all items that would be put in mUserBackgroundItems for that user. final SparseArray<MergedItem> mOtherUserBackgroundItems = new SparseArray<MergedItem>(); - // Tracking of information about users. - final SparseArray<UserState> mUsers = new SparseArray<UserState>(); - static class AppProcessInfo { final ActivityManager.RunningAppProcessInfo info; boolean hasServices; @@ -286,6 +283,42 @@ public class RunningState { } }; + private final class UserManagerBroadcastReceiver extends BroadcastReceiver { + private volatile boolean usersChanged; + + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + if (mResumed) { + mHaveData = false; + mBackgroundHandler.removeMessages(MSG_RESET_CONTENTS); + mBackgroundHandler.sendEmptyMessage(MSG_RESET_CONTENTS); + mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS); + mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS); + } else { + usersChanged = true; + } + } + } + + public boolean checkUsersChangedLocked() { + boolean oldValue = usersChanged; + usersChanged = false; + return oldValue; + } + + void register(Context context) { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_STOPPED); + filter.addAction(Intent.ACTION_USER_STARTED); + filter.addAction(Intent.ACTION_USER_INFO_CHANGED); + context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null); + } + } + + private final UserManagerBroadcastReceiver mUmBroadcastReceiver = + new UserManagerBroadcastReceiver(); + // ----- DATA STRUCTURES ----- static interface OnRefreshUiListener { @@ -327,7 +360,9 @@ public class RunningState { public Drawable loadIcon(Context context, RunningState state) { if (mPackageInfo != null) { - return mPackageInfo.loadIcon(state.mPm); + Drawable unbadgedIcon = mPackageInfo.loadUnbadgedIcon(state.mPm); + Drawable icon = state.mPm.getUserBadgedIcon(unbadgedIcon, new UserHandle(mUserId)); + return icon; } return null; } @@ -750,15 +785,17 @@ public class RunningState { mBackgroundThread = new HandlerThread("RunningState:Background"); mBackgroundThread.start(); mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper()); + mUmBroadcastReceiver.register(mApplicationContext); } void resume(OnRefreshUiListener listener) { synchronized (mLock) { mResumed = true; mRefreshUiListener = listener; - // TODO: The set of users may have changed too, so we should probably recompute it - // each time, but that might be costly. See http://b/18696308 - if (mInterestingConfigChanges.applyNewConfig(mApplicationContext.getResources())) { + boolean usersChanged = mUmBroadcastReceiver.checkUsersChangedLocked(); + boolean configChanged = + mInterestingConfigChanges.applyNewConfig(mApplicationContext.getResources()); + if (usersChanged || configChanged) { mHaveData = false; mBackgroundHandler.removeMessages(MSG_RESET_CONTENTS); mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS); @@ -824,7 +861,6 @@ public class RunningState { mRunningProcesses.clear(); mProcessItems.clear(); mAllProcessItems.clear(); - mUsers.clear(); } private void addOtherUserItem(Context context, ArrayList<MergedItem> newMergedItems, @@ -832,9 +868,7 @@ public class RunningState { MergedItem userItem = userItems.get(newItem.mUserId); boolean first = userItem == null || userItem.mCurSeq != mSequence; if (first) { - UserState userState = mUsers.get(newItem.mUserId); - UserInfo info = userState != null - ? userState.mInfo : mUm.getUserInfo(newItem.mUserId); + UserInfo info = mUm.getUserInfo(newItem.mUserId); if (info == null) { // The user no longer exists, skip return; @@ -849,12 +883,10 @@ public class RunningState { userItem.mChildren.clear(); } userItem.mCurSeq = mSequence; - if (userState == null) { - userItem.mUser = new UserState(); - userItem.mUser.mInfo = info; - userItem.mUser.mIcon = Utils.getUserIcon(context, mUm, info); - userItem.mUser.mLabel = Utils.getUserLabel(context, info); - } + userItem.mUser = new UserState(); + userItem.mUser.mInfo = info; + userItem.mUser.mIcon = Utils.getUserIcon(context, mUm, info); + userItem.mUser.mLabel = Utils.getUserLabel(context, info); newMergedItems.add(userItem); } userItem.mChildren.add(newItem); @@ -1403,12 +1435,6 @@ public class RunningState { return changed; } - ArrayList<BaseItem> getCurrentItems() { - synchronized (mLock) { - return mItems; - } - } - void setWatchingBackgroundItems(boolean watching) { synchronized (mLock) { mWatchingBackgroundItems = watching; diff --git a/src/com/android/settings/bluetooth/A2dpProfile.java b/src/com/android/settings/bluetooth/A2dpProfile.java deleted file mode 100755 index 435a659..0000000 --- a/src/com/android/settings/bluetooth/A2dpProfile.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.os.ParcelUuid; -import android.util.Log; - -import com.android.settings.R; - -import java.util.ArrayList; -import java.util.List; - -final class A2dpProfile implements LocalBluetoothProfile { - private static final String TAG = "A2dpProfile"; - private static boolean V = true; - - private BluetoothA2dp mService; - private boolean mIsProfileReady; - - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - - static final ParcelUuid[] SINK_UUIDS = { - BluetoothUuid.AudioSink, - BluetoothUuid.AdvAudioDist, - }; - - static final String NAME = "A2DP"; - private final LocalBluetoothProfileManager mProfileManager; - - // Order of this profile in device profiles list - private static final int ORDINAL = 1; - - // These callbacks run on the main thread. - private final class A2dpServiceListener - implements BluetoothProfile.ServiceListener { - - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothA2dp) proxy; - // We just bound to the service, so refresh the UI for any connected A2DP devices. - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - while (!deviceList.isEmpty()) { - BluetoothDevice nextDevice = deviceList.remove(0); - CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); - // we may add a new device here, but generally this should not happen - if (device == null) { - Log.w(TAG, "A2dpProfile found new device: " + nextDevice); - device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); - } - device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED); - device.refresh(); - } - mIsProfileReady=true; - } - - public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - return mIsProfileReady; - } - - A2dpProfile(Context context, LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, - LocalBluetoothProfileManager profileManager) { - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mProfileManager = profileManager; - mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(), - BluetoothProfile.A2DP); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return true; - } - - public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); - return mService.getDevicesMatchingConnectionStates( - new int[] {BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTING}); - } - - public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> sinks = getConnectedDevices(); - if (sinks != null) { - for (BluetoothDevice sink : sinks) { - mService.disconnect(sink); - } - } - return mService.connect(device); - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - return mService.disconnect(device); - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) { - return BluetoothProfile.STATE_DISCONNECTED; - } - return mService.getConnectionState(device); - } - - public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; - } - - public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; - if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); - } - } - boolean isA2dpPlaying() { - if (mService == null) return false; - List<BluetoothDevice> sinks = mService.getConnectedDevices(); - if (!sinks.isEmpty()) { - if (mService.isA2dpPlaying(sinks.get(0))) { - return true; - } - } - return false; - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - return R.string.bluetooth_profile_a2dp; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - int state = getConnectionStatus(device); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return R.string.bluetooth_a2dp_profile_summary_use_for; - - case BluetoothProfile.STATE_CONNECTED: - return R.string.bluetooth_a2dp_profile_summary_connected; - - default: - return Utils.getConnectionStateSummary(state); - } - } - - public int getDrawableResource(BluetoothClass btClass) { - return R.drawable.ic_bt_headphones_a2dp; - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP, - mService); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up A2DP proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/BluetoothCallback.java b/src/com/android/settings/bluetooth/BluetoothCallback.java deleted file mode 100644 index 3ce9adf..0000000 --- a/src/com/android/settings/bluetooth/BluetoothCallback.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -/** - * BluetoothCallback provides a callback interface for the settings - * UI to receive events from {@link BluetoothEventManager}. - */ -interface BluetoothCallback { - void onBluetoothStateChanged(int bluetoothState); - void onScanningStateChanged(boolean started); - void onDeviceAdded(CachedBluetoothDevice cachedDevice); - void onDeviceDeleted(CachedBluetoothDevice cachedDevice); - void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState); -} diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java b/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java deleted file mode 100644 index e4f11a2..0000000 --- a/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothUuid; -import android.os.ParcelUuid; -import android.util.Log; - -/** - * BluetoothDeviceFilter contains a static method that returns a - * Filter object that returns whether or not the BluetoothDevice - * passed to it matches the specified filter type constant from - * {@link android.bluetooth.BluetoothDevicePicker}. - */ -final class BluetoothDeviceFilter { - private static final String TAG = "BluetoothDeviceFilter"; - - /** The filter interface to external classes. */ - interface Filter { - boolean matches(BluetoothDevice device); - } - - /** All filter singleton (referenced directly). */ - static final Filter ALL_FILTER = new AllFilter(); - - /** Bonded devices only filter (referenced directly). */ - static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter(); - - /** Unbonded devices only filter (referenced directly). */ - static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter(); - - /** Table of singleton filter objects. */ - private static final Filter[] FILTERS = { - ALL_FILTER, // FILTER_TYPE_ALL - new AudioFilter(), // FILTER_TYPE_AUDIO - new TransferFilter(), // FILTER_TYPE_TRANSFER - new PanuFilter(), // FILTER_TYPE_PANU - new NapFilter() // FILTER_TYPE_NAP - }; - - /** Private constructor. */ - private BluetoothDeviceFilter() { - } - - /** - * Returns the singleton {@link Filter} object for the specified type, - * or {@link #ALL_FILTER} if the type value is out of range. - * - * @param filterType a constant from BluetoothDevicePicker - * @return a singleton object implementing the {@link Filter} interface. - */ - static Filter getFilter(int filterType) { - if (filterType >= 0 && filterType < FILTERS.length) { - return FILTERS[filterType]; - } else { - Log.w(TAG, "Invalid filter type " + filterType + " for device picker"); - return ALL_FILTER; - } - } - - /** Filter that matches all devices. */ - private static final class AllFilter implements Filter { - public boolean matches(BluetoothDevice device) { - return true; - } - } - - /** Filter that matches only bonded devices. */ - private static final class BondedDeviceFilter implements Filter { - public boolean matches(BluetoothDevice device) { - return device.getBondState() == BluetoothDevice.BOND_BONDED; - } - } - - /** Filter that matches only unbonded devices. */ - private static final class UnbondedDeviceFilter implements Filter { - public boolean matches(BluetoothDevice device) { - return device.getBondState() != BluetoothDevice.BOND_BONDED; - } - } - - /** Parent class of filters based on UUID and/or Bluetooth class. */ - private abstract static class ClassUuidFilter implements Filter { - abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass); - - public boolean matches(BluetoothDevice device) { - return matches(device.getUuids(), device.getBluetoothClass()); - } - } - - /** Filter that matches devices that support AUDIO profiles. */ - private static final class AudioFilter extends ClassUuidFilter { - @Override - boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { - if (uuids != null) { - if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) { - return true; - } - if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) { - return true; - } - } else if (btClass != null) { - if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) || - btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { - return true; - } - } - return false; - } - } - - /** Filter that matches devices that support Object Transfer. */ - private static final class TransferFilter extends ClassUuidFilter { - @Override - boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { - if (uuids != null) { - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) { - return true; - } - } - return btClass != null - && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP); - } - } - - /** Filter that matches devices that support PAN User (PANU) profile. */ - private static final class PanuFilter extends ClassUuidFilter { - @Override - boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { - if (uuids != null) { - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) { - return true; - } - } - return btClass != null - && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU); - } - } - - /** Filter that matches devices that support NAP profile. */ - private static final class NapFilter extends ClassUuidFilter { - @Override - boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { - if (uuids != null) { - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) { - return true; - } - } - return btClass != null - && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP); - } - } -} diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 5d6b17c..67c026b 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -37,6 +37,11 @@ import android.widget.ImageView; import com.android.settings.R; import com.android.settings.search.Index; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.HeadsetProfile; +import com.android.settingslib.bluetooth.HidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothProfile; import java.util.List; diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java index 17da0a7..6841b54 100755 --- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java @@ -25,12 +25,11 @@ import android.content.SharedPreferences; import android.os.Handler; import android.os.SystemProperties; import android.preference.Preference; -import android.text.format.DateUtils; +import android.util.Log; import com.android.settings.R; - -import android.text.format.Time; -import android.util.Log; +import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; /** * BluetoothDiscoverableEnabler is a helper to manage the "Discoverable" diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableTimeoutReceiver.java deleted file mode 100644 index 14f7b22..0000000 --- a/src/com/android/settings/bluetooth/BluetoothDiscoverableTimeoutReceiver.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.settings.bluetooth; - -/* Required to handle timeout notification when phone is suspended */ -import android.app.AlarmManager; -import android.app.PendingIntent; - -import android.bluetooth.BluetoothAdapter; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - - -public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver { - private static final String TAG = "BluetoothDiscoverableTimeoutReceiver"; - - private static final String INTENT_DISCOVERABLE_TIMEOUT = - "android.bluetooth.intent.DISCOVERABLE_TIMEOUT"; - - static void setDiscoverableAlarm(Context context, long alarmTime) { - Log.d(TAG, "setDiscoverableAlarm(): alarmTime = " + alarmTime); - - Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT); - intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class); - PendingIntent pending = PendingIntent.getBroadcast( - context, 0, intent, 0); - AlarmManager alarmManager = - (AlarmManager) context.getSystemService (Context.ALARM_SERVICE); - - if (pending != null) { - // Cancel any previous alarms that do the same thing. - alarmManager.cancel(pending); - Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm"); - } - pending = PendingIntent.getBroadcast( - context, 0, intent, 0); - - alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending); - } - - static void cancelDiscoverableAlarm(Context context) { - Log.d(TAG, "cancelDiscoverableAlarm(): Enter"); - - Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT); - intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class); - PendingIntent pending = PendingIntent.getBroadcast( - context, 0, intent, PendingIntent.FLAG_NO_CREATE); - if (pending != null) { - // Cancel any previous alarms that do the same thing. - AlarmManager alarmManager = - (AlarmManager) context.getSystemService (Context.ALARM_SERVICE); - - alarmManager.cancel(pending); - } - } - - @Override - public void onReceive(Context context, Intent intent) { - LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance(); - - if(localBluetoothAdapter != null && - localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { - Log.d(TAG, "Disable discoverable..."); - - localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE); - } else { - Log.e(TAG, "localBluetoothAdapter is NULL!!"); - } - } -}; diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java b/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java index fbb6827..1ba9f85 100644 --- a/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java +++ b/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java @@ -22,6 +22,8 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +import com.android.settingslib.bluetooth.BluetoothEventManager; + /** * BluetoothDiscoveryReceiver updates a timestamp when the * Bluetooth adapter starts or finishes discovery mode. This diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java index b006c65..1c9eeb6 100644 --- a/src/com/android/settings/bluetooth/BluetoothEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java @@ -24,14 +24,15 @@ import android.content.IntentFilter; import android.os.Handler; import android.os.Message; import android.provider.Settings; -import android.widget.CompoundButton; import android.widget.Switch; import android.widget.Toast; import com.android.settings.R; -import com.android.settings.WirelessSettings; import com.android.settings.search.Index; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.WirelessUtils; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox @@ -78,7 +79,7 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener mSwitch = switchBar.getSwitch(); mValidListener = false; - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context); + LocalBluetoothManager manager = Utils.getLocalBtManager(context); if (manager == null) { // Bluetooth is not supported mLocalAdapter = null; @@ -177,7 +178,7 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener public void onSwitchChanged(Switch switchView, boolean isChecked) { // Show toast message if Bluetooth is not allowed in airplane mode if (isChecked && - !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { + !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); // Reset switch to off switchView.setChecked(false); diff --git a/src/com/android/settings/bluetooth/BluetoothEventManager.java b/src/com/android/settings/bluetooth/BluetoothEventManager.java deleted file mode 100755 index bf7606e..0000000 --- a/src/com/android/settings/bluetooth/BluetoothEventManager.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import com.android.settings.R; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth - * API and dispatches the event on the UI thread to the right class in the - * Settings. - */ -final class BluetoothEventManager { - private static final String TAG = "BluetoothEventManager"; - - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - private LocalBluetoothProfileManager mProfileManager; - private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter; - private final Map<String, Handler> mHandlerMap; - private Context mContext; - - private final Collection<BluetoothCallback> mCallbacks = - new ArrayList<BluetoothCallback>(); - - interface Handler { - void onReceive(Context context, Intent intent, BluetoothDevice device); - } - - void addHandler(String action, Handler handler) { - mHandlerMap.put(action, handler); - mAdapterIntentFilter.addAction(action); - } - - void addProfileHandler(String action, Handler handler) { - mHandlerMap.put(action, handler); - mProfileIntentFilter.addAction(action); - } - - // Set profile manager after construction due to circular dependency - void setProfileManager(LocalBluetoothProfileManager manager) { - mProfileManager = manager; - } - - BluetoothEventManager(LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, Context context) { - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mAdapterIntentFilter = new IntentFilter(); - mProfileIntentFilter = new IntentFilter(); - mHandlerMap = new HashMap<String, Handler>(); - mContext = context; - - // Bluetooth on/off broadcasts - addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler()); - - // Discovery broadcasts - addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true)); - addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false)); - addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler()); - addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler()); - addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler()); - - // Pairing broadcasts - addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler()); - addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler()); - - // Fine-grained state broadcasts - addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler()); - addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler()); - - // Dock event broadcasts - addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler()); - - mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter); - } - - void registerProfileIntentReceiver() { - mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter); - } - - /** Register to start receiving callbacks for Bluetooth events. */ - void registerCallback(BluetoothCallback callback) { - synchronized (mCallbacks) { - mCallbacks.add(callback); - } - } - - /** Unregister to stop receiving callbacks for Bluetooth events. */ - void unregisterCallback(BluetoothCallback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } - } - - // This can't be called from a broadcast receiver where the filter is set in the Manifest. - private static String getDockedDeviceAddress(Context context) { - // This works only because these broadcast intents are "sticky" - Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); - if (i != null) { - int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { - BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (device != null) { - return device.getAddress(); - } - } - } - return null; - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - BluetoothDevice device = intent - .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - - Handler handler = mHandlerMap.get(action); - if (handler != null) { - handler.onReceive(context, intent, device); - } - } - }; - - private class AdapterStateChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - // update local profiles and get paired devices - mLocalAdapter.setBluetoothStateInt(state); - // send callback to update UI and possibly start scanning - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onBluetoothStateChanged(state); - } - } - // Inform CachedDeviceManager that the adapter state has changed - mDeviceManager.onBluetoothStateChanged(state); - } - } - - private class ScanningStateChangedHandler implements Handler { - private final boolean mStarted; - - ScanningStateChangedHandler(boolean started) { - mStarted = started; - } - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onScanningStateChanged(mStarted); - } - } - mDeviceManager.onScanningStateChanged(mStarted); - LocalBluetoothPreferences.persistDiscoveringTimestamp(context); - } - } - - private class DeviceFoundHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE); - BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS); - String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME); - // TODO Pick up UUID. They should be available for 2.1 devices. - // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1. - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device); - Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: " - + cachedDevice); - // callback to UI to create Preference for new device - dispatchDeviceAdded(cachedDevice); - } - cachedDevice.setRssi(rssi); - cachedDevice.setBtClass(btClass); - cachedDevice.setNewName(name); - cachedDevice.setVisible(true); - } - } - - private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceAdded(cachedDevice); - } - } - } - - private class DeviceDisappearedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device); - return; - } - if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceDeleted(cachedDevice); - } - } - } - } - } - - private class NameChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - mDeviceManager.onDeviceNameUpdated(device); - } - } - - private class BondStateChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - if (device == null) { - Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE"); - return; - } - int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, - BluetoothDevice.ERROR); - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - Log.w(TAG, "CachedBluetoothDevice for device " + device + - " not found, calling readPairedDevices()."); - if (!readPairedDevices()) { - Log.e(TAG, "Got bonding state changed for " + device + - ", but we have no record of that device."); - return; - } - cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - Log.e(TAG, "Got bonding state changed for " + device + - ", but device not added in cache."); - return; - } - } - - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceBondStateChanged(cachedDevice, bondState); - } - } - cachedDevice.onBondingStateChanged(bondState); - - if (bondState == BluetoothDevice.BOND_NONE) { - if (device.isBluetoothDock()) { - // After a dock is unpaired, we will forget the settings - LocalBluetoothPreferences - .removeDockAutoConnectSetting(context, device.getAddress()); - - // if the device is undocked, remove it from the list as well - if (!device.getAddress().equals(getDockedDeviceAddress(context))) { - cachedDevice.setVisible(false); - } - } - int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON, - BluetoothDevice.ERROR); - - showUnbondMessage(context, cachedDevice.getName(), reason); - } - } - - /** - * Called when we have reached the unbonded state. - * - * @param reason one of the error reasons from - * BluetoothDevice.UNBOND_REASON_* - */ - private void showUnbondMessage(Context context, String name, int reason) { - int errorMsg; - - switch(reason) { - case BluetoothDevice.UNBOND_REASON_AUTH_FAILED: - errorMsg = R.string.bluetooth_pairing_pin_error_message; - break; - case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED: - errorMsg = R.string.bluetooth_pairing_rejected_error_message; - break; - case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN: - errorMsg = R.string.bluetooth_pairing_device_down_error_message; - break; - case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS: - case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT: - case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS: - case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED: - errorMsg = R.string.bluetooth_pairing_error_message; - break; - default: - Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason); - return; - } - Utils.showError(context, name, errorMsg); - } - } - - private class ClassChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - mDeviceManager.onBtClassChanged(device); - } - } - - private class UuidChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - mDeviceManager.onUuidChanged(device); - } - } - - private class PairingCancelHandler implements Handler { - public void onReceive(Context context, Intent intent, BluetoothDevice device) { - if (device == null) { - Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE"); - return; - } - int errorMsg = R.string.bluetooth_pairing_error_message; - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - Utils.showError(context, cachedDevice.getName(), errorMsg); - } - } - - private class DockEventHandler implements Handler { - public void onReceive(Context context, Intent intent, BluetoothDevice device) { - // Remove if unpair device upon undocking - int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1; - int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked); - if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { - if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) { - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice != null) { - cachedDevice.setVisible(false); - } - } - } - } - } - boolean readPairedDevices() { - Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices(); - if (bondedDevices == null) { - return false; - } - - boolean deviceAdded = false; - for (BluetoothDevice device : bondedDevices) { - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device); - dispatchDeviceAdded(cachedDevice); - deviceAdded = true; - } - } - - return deviceAdded; - } -} diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java index 4466aea..879cd9d 100644 --- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java @@ -40,6 +40,8 @@ import android.widget.EditText; import android.widget.TextView; import com.android.settings.R; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * Dialog fragment for renaming the local Bluetooth device. @@ -80,7 +82,7 @@ public final class BluetoothNameDialogFragment extends DialogFragment implements }; public BluetoothNameDialogFragment() { - LocalBluetoothManager localManager = LocalBluetoothManager.getInstance(getActivity()); + LocalBluetoothManager localManager = Utils.getLocalBtManager(getActivity()); mLocalAdapter = localManager.getBluetoothAdapter(); } diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java index 6f5c136..5b54c32 100755 --- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java @@ -43,6 +43,9 @@ import android.widget.TextView; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.settings.R; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + import android.view.KeyEvent; import java.util.Locale; @@ -103,7 +106,7 @@ public final class BluetoothPairingDialog extends AlertActivity implements return; } - mBluetoothManager = LocalBluetoothManager.getInstance(this); + mBluetoothManager = Utils.getLocalBtManager(this); if (mBluetoothManager == null) { Log.e(TAG, "Error: BluetoothAdapter not supported by system"); finish(); diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java index f43d176..7a1e69d 100755 --- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java +++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java @@ -31,8 +31,10 @@ import android.widget.Button; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; - import com.android.settings.R; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * BluetoothPermissionActivity shows a dialog for accepting incoming @@ -192,7 +194,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements boolean always = true; if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) { - LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(this); + LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(this); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java index 12c1d77..e436b79 100644 --- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java +++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java @@ -28,6 +28,9 @@ import android.os.UserManager; import android.util.Log; import com.android.settings.R; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * BluetoothPermissionRequest is a receiver to receive Bluetooth connection @@ -200,7 +203,7 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { return processed; } - LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(mContext); + LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(mContext); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java index dd2c9df..c85e515 100755 --- a/src/com/android/settings/bluetooth/BluetoothSettings.java +++ b/src/com/android/settings/bluetooth/BluetoothSettings.java @@ -28,12 +28,9 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceCategory; -import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.util.Log; @@ -44,17 +41,18 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.search.Index; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.bluetooth.BluetoothDeviceFilter; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.ArrayList; import java.util.List; @@ -506,7 +504,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem result.add(data); // Add cached paired BT devices - LocalBluetoothManager lbtm = LocalBluetoothManager.getInstance(context); + LocalBluetoothManager lbtm = Utils.getLocalBtManager(context); // LocalBluetoothManager.getInstance can return null if the device does not // support bluetooth (e.g. the emulator). if (lbtm != null) { diff --git a/src/com/android/settings/bluetooth/BluetoothVisibilityTimeoutFragment.java b/src/com/android/settings/bluetooth/BluetoothVisibilityTimeoutFragment.java deleted file mode 100644 index a65c6c1..0000000 --- a/src/com/android/settings/bluetooth/BluetoothVisibilityTimeoutFragment.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.bluetooth.BluetoothAdapter; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.text.Editable; -import android.text.InputFilter; -import android.text.TextWatcher; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import com.android.internal.app.AlertController; -import com.android.settings.R; - -/** - * Dialog fragment for setting the discoverability timeout. - */ -public final class BluetoothVisibilityTimeoutFragment extends DialogFragment - implements DialogInterface.OnClickListener { - - private final BluetoothDiscoverableEnabler mDiscoverableEnabler; - - public BluetoothVisibilityTimeoutFragment() { - mDiscoverableEnabler = LocalBluetoothManager.getInstance(getActivity()) - .getDiscoverableEnabler(); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.bluetooth_visibility_timeout) - .setSingleChoiceItems(R.array.bluetooth_visibility_timeout_entries, - mDiscoverableEnabler.getDiscoverableTimeoutIndex(), this) - .setNegativeButton(android.R.string.cancel, null) - .create(); - } - - public void onClick(DialogInterface dialog, int which) { - mDiscoverableEnabler.setDiscoverableTimeout(which); - dismiss(); - } -} diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java deleted file mode 100755 index f33f4db..0000000 --- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java +++ /dev/null @@ -1,787 +0,0 @@ -/* - * 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.ParcelUuid; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.Log; -import android.bluetooth.BluetoothAdapter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -/** - * CachedBluetoothDevice represents a remote Bluetooth device. It contains - * attributes of the device (such as the address, name, RSSI, etc.) and - * functionality that can be performed on the device (connect, pair, disconnect, - * etc.). - */ -final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { - private static final String TAG = "CachedBluetoothDevice"; - private static final boolean DEBUG = Utils.V; - - private final Context mContext; - private final LocalBluetoothAdapter mLocalAdapter; - private final LocalBluetoothProfileManager mProfileManager; - private final BluetoothDevice mDevice; - private String mName; - private short mRssi; - private BluetoothClass mBtClass; - private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState; - - private final List<LocalBluetoothProfile> mProfiles = - new ArrayList<LocalBluetoothProfile>(); - - // List of profiles that were previously in mProfiles, but have been removed - private final List<LocalBluetoothProfile> mRemovedProfiles = - new ArrayList<LocalBluetoothProfile>(); - - // Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP - private boolean mLocalNapRoleConnected; - - private boolean mVisible; - - private int mPhonebookPermissionChoice; - - private int mMessagePermissionChoice; - - private int mMessageRejectionCount; - - private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); - - // Following constants indicate the user's choices of Phone book/message access settings - // User hasn't made any choice or settings app has wiped out the memory - public final static int ACCESS_UNKNOWN = 0; - // User has accepted the connection and let Settings app remember the decision - public final static int ACCESS_ALLOWED = 1; - // User has rejected the connection and let Settings app remember the decision - public final static int ACCESS_REJECTED = 2; - - // How many times user should reject the connection to make the choice persist. - private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2; - - private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject"; - - /** - * When we connect to multiple profiles, we only want to display a single - * error even if they all fail. This tracks that state. - */ - private boolean mIsConnectingErrorPossible; - - /** - * Last time a bt profile auto-connect was attempted. - * If an ACTION_UUID intent comes in within - * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect - * again with the new UUIDs - */ - private long mConnectAttempted; - - // See mConnectAttempted - private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000; - - /** Auto-connect after pairing only if locally initiated. */ - private boolean mConnectAfterPairing; - - /** - * Describes the current device and profile for logging. - * - * @param profile Profile to describe - * @return Description of the device and profile - */ - private String describe(LocalBluetoothProfile profile) { - StringBuilder sb = new StringBuilder(); - sb.append("Address:").append(mDevice); - if (profile != null) { - sb.append(" Profile:").append(profile); - } - - return sb.toString(); - } - - void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) { - if (Utils.D) { - Log.d(TAG, "onProfileStateChanged: profile " + profile + - " newProfileState " + newProfileState); - } - if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) - { - if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored..."); - return; - } - mProfileConnectionState.put(profile, newProfileState); - if (newProfileState == BluetoothProfile.STATE_CONNECTED) { - if (profile instanceof MapProfile) { - profile.setPreferred(mDevice, true); - } else if (!mProfiles.contains(profile)) { - mRemovedProfiles.remove(profile); - mProfiles.add(profile); - if (profile instanceof PanProfile && - ((PanProfile) profile).isLocalRoleNap(mDevice)) { - // Device doesn't support NAP, so remove PanProfile on disconnect - mLocalNapRoleConnected = true; - } - } - } else if (profile instanceof MapProfile && - newProfileState == BluetoothProfile.STATE_DISCONNECTED) { - profile.setPreferred(mDevice, false); - } else if (mLocalNapRoleConnected && profile instanceof PanProfile && - ((PanProfile) profile).isLocalRoleNap(mDevice) && - newProfileState == BluetoothProfile.STATE_DISCONNECTED) { - Log.d(TAG, "Removing PanProfile from device after NAP disconnect"); - mProfiles.remove(profile); - mRemovedProfiles.add(profile); - mLocalNapRoleConnected = false; - } - } - - CachedBluetoothDevice(Context context, - LocalBluetoothAdapter adapter, - LocalBluetoothProfileManager profileManager, - BluetoothDevice device) { - mContext = context; - mLocalAdapter = adapter; - mProfileManager = profileManager; - mDevice = device; - mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>(); - fillData(); - } - - void disconnect() { - for (LocalBluetoothProfile profile : mProfiles) { - disconnect(profile); - } - // Disconnect PBAP server in case its connected - // This is to ensure all the profiles are disconnected as some CK/Hs do not - // disconnect PBAP connection when HF connection is brought down - PbapServerProfile PbapProfile = mProfileManager.getPbapProfile(); - if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED) - { - PbapProfile.disconnect(mDevice); - } - } - - void disconnect(LocalBluetoothProfile profile) { - if (profile.disconnect(mDevice)) { - if (Utils.D) { - Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile)); - } - } - } - - void connect(boolean connectAllProfiles) { - if (!ensurePaired()) { - return; - } - - mConnectAttempted = SystemClock.elapsedRealtime(); - connectWithoutResettingTimer(connectAllProfiles); - } - - void onBondingDockConnect() { - // Attempt to connect if UUIDs are available. Otherwise, - // we will connect when the ACTION_UUID intent arrives. - connect(false); - } - - private void connectWithoutResettingTimer(boolean connectAllProfiles) { - // Try to initialize the profiles if they were not. - if (mProfiles.isEmpty()) { - // if mProfiles is empty, then do not invoke updateProfiles. This causes a race - // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated - // from bluetooth stack but ACTION.uuid is not sent yet. - // Eventually ACTION.uuid will be received which shall trigger the connection of the - // various profiles - // If UUIDs are not available yet, connect will be happen - // upon arrival of the ACTION_UUID intent. - Log.d(TAG, "No profiles. Maybe we will connect later"); - return; - } - - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; - - int preferredProfiles = 0; - for (LocalBluetoothProfile profile : mProfiles) { - if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) { - if (profile.isPreferred(mDevice)) { - ++preferredProfiles; - connectInt(profile); - } - } - } - if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles); - - if (preferredProfiles == 0) { - connectAutoConnectableProfiles(); - } - } - - private void connectAutoConnectableProfiles() { - if (!ensurePaired()) { - return; - } - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; - - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.isAutoConnectable()) { - profile.setPreferred(mDevice, true); - connectInt(profile); - } - } - } - - /** - * Connect this device to the specified profile. - * - * @param profile the profile to use with the remote device - */ - void connectProfile(LocalBluetoothProfile profile) { - mConnectAttempted = SystemClock.elapsedRealtime(); - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; - connectInt(profile); - // Refresh the UI based on profile.connect() call - refresh(); - } - - synchronized void connectInt(LocalBluetoothProfile profile) { - if (!ensurePaired()) { - return; - } - if (profile.connect(mDevice)) { - if (Utils.D) { - Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile)); - } - return; - } - Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName); - } - - private boolean ensurePaired() { - if (getBondState() == BluetoothDevice.BOND_NONE) { - startPairing(); - return false; - } else { - return true; - } - } - - boolean startPairing() { - // Pairing is unreliable while scanning, so cancel discovery - if (mLocalAdapter.isDiscovering()) { - mLocalAdapter.cancelDiscovery(); - } - - if (!mDevice.createBond()) { - return false; - } - - mConnectAfterPairing = true; // auto-connect after pairing - return true; - } - - /** - * Return true if user initiated pairing on this device. The message text is - * slightly different for local vs. remote initiated pairing dialogs. - */ - boolean isUserInitiatedPairing() { - return mConnectAfterPairing; - } - - void unpair() { - int state = getBondState(); - - if (state == BluetoothDevice.BOND_BONDING) { - mDevice.cancelBondProcess(); - } - - if (state != BluetoothDevice.BOND_NONE) { - final BluetoothDevice dev = mDevice; - if (dev != null) { - final boolean successful = dev.removeBond(); - if (successful) { - if (Utils.D) { - Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null)); - } - } else if (Utils.V) { - Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " + - describe(null)); - } - } - } - } - - int getProfileConnectionState(LocalBluetoothProfile profile) { - if (mProfileConnectionState == null || - mProfileConnectionState.get(profile) == null) { - // If cache is empty make the binder call to get the state - int state = profile.getConnectionStatus(mDevice); - mProfileConnectionState.put(profile, state); - } - return mProfileConnectionState.get(profile); - } - - public void clearProfileConnectionState () - { - if (Utils.D) { - Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName()); - } - for (LocalBluetoothProfile profile :getProfiles()) { - mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED); - } - } - - // TODO: do any of these need to run async on a background thread? - private void fillData() { - fetchName(); - fetchBtClass(); - updateProfiles(); - migratePhonebookPermissionChoice(); - migrateMessagePermissionChoice(); - fetchMessageRejectionCount(); - - mVisible = false; - dispatchAttributesChanged(); - } - - BluetoothDevice getDevice() { - return mDevice; - } - - String getName() { - return mName; - } - - /** - * Populate name from BluetoothDevice.ACTION_FOUND intent - */ - void setNewName(String name) { - if (mName == null) { - mName = name; - if (mName == null || TextUtils.isEmpty(mName)) { - mName = mDevice.getAddress(); - } - dispatchAttributesChanged(); - } - } - - /** - * user changes the device name - */ - void setName(String name) { - if (!mName.equals(name)) { - mName = name; - mDevice.setAlias(name); - dispatchAttributesChanged(); - } - } - - void refreshName() { - fetchName(); - dispatchAttributesChanged(); - } - - private void fetchName() { - mName = mDevice.getAliasName(); - - if (TextUtils.isEmpty(mName)) { - mName = mDevice.getAddress(); - if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName); - } - } - - void refresh() { - dispatchAttributesChanged(); - } - - boolean isVisible() { - return mVisible; - } - - void setVisible(boolean visible) { - if (mVisible != visible) { - mVisible = visible; - dispatchAttributesChanged(); - } - } - - int getBondState() { - return mDevice.getBondState(); - } - - void setRssi(short rssi) { - if (mRssi != rssi) { - mRssi = rssi; - dispatchAttributesChanged(); - } - } - - /** - * Checks whether we are connected to this device (any profile counts). - * - * @return Whether it is connected. - */ - boolean isConnected() { - for (LocalBluetoothProfile profile : mProfiles) { - int status = getProfileConnectionState(profile); - if (status == BluetoothProfile.STATE_CONNECTED) { - return true; - } - } - - return false; - } - - boolean isConnectedProfile(LocalBluetoothProfile profile) { - int status = getProfileConnectionState(profile); - return status == BluetoothProfile.STATE_CONNECTED; - - } - - boolean isBusy() { - for (LocalBluetoothProfile profile : mProfiles) { - int status = getProfileConnectionState(profile); - if (status == BluetoothProfile.STATE_CONNECTING - || status == BluetoothProfile.STATE_DISCONNECTING) { - return true; - } - } - return getBondState() == BluetoothDevice.BOND_BONDING; - } - - /** - * Fetches a new value for the cached BT class. - */ - private void fetchBtClass() { - mBtClass = mDevice.getBluetoothClass(); - } - - private boolean updateProfiles() { - ParcelUuid[] uuids = mDevice.getUuids(); - if (uuids == null) return false; - - ParcelUuid[] localUuids = mLocalAdapter.getUuids(); - if (localUuids == null) return false; - - /** - * Now we know if the device supports PBAP, update permissions... - */ - processPhonebookAccess(); - - mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles, - mLocalNapRoleConnected, mDevice); - - if (DEBUG) { - Log.e(TAG, "updating profiles for " + mDevice.getAliasName()); - BluetoothClass bluetoothClass = mDevice.getBluetoothClass(); - - if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString()); - Log.v(TAG, "UUID:"); - for (ParcelUuid uuid : uuids) { - Log.v(TAG, " " + uuid); - } - } - return true; - } - - /** - * Refreshes the UI for the BT class, including fetching the latest value - * for the class. - */ - void refreshBtClass() { - fetchBtClass(); - dispatchAttributesChanged(); - } - - /** - * Refreshes the UI when framework alerts us of a UUID change. - */ - void onUuidChanged() { - updateProfiles(); - - if (DEBUG) { - Log.e(TAG, "onUuidChanged: Time since last connect" - + (SystemClock.elapsedRealtime() - mConnectAttempted)); - } - - /* - * If a connect was attempted earlier without any UUID, we will do the - * connect now. - */ - if (!mProfiles.isEmpty() - && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock - .elapsedRealtime()) { - connectWithoutResettingTimer(false); - } - dispatchAttributesChanged(); - } - - void onBondingStateChanged(int bondState) { - if (bondState == BluetoothDevice.BOND_NONE) { - mProfiles.clear(); - mConnectAfterPairing = false; // cancel auto-connect - setPhonebookPermissionChoice(ACCESS_UNKNOWN); - setMessagePermissionChoice(ACCESS_UNKNOWN); - mMessageRejectionCount = 0; - saveMessageRejectionCount(); - } - - refresh(); - - if (bondState == BluetoothDevice.BOND_BONDED) { - if (mDevice.isBluetoothDock()) { - onBondingDockConnect(); - } else if (mConnectAfterPairing) { - connect(false); - } - mConnectAfterPairing = false; - } - } - - void setBtClass(BluetoothClass btClass) { - if (btClass != null && mBtClass != btClass) { - mBtClass = btClass; - dispatchAttributesChanged(); - } - } - - BluetoothClass getBtClass() { - return mBtClass; - } - - List<LocalBluetoothProfile> getProfiles() { - return Collections.unmodifiableList(mProfiles); - } - - List<LocalBluetoothProfile> getConnectableProfiles() { - List<LocalBluetoothProfile> connectableProfiles = - new ArrayList<LocalBluetoothProfile>(); - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.isConnectable()) { - connectableProfiles.add(profile); - } - } - return connectableProfiles; - } - - List<LocalBluetoothProfile> getRemovedProfiles() { - return mRemovedProfiles; - } - - void registerCallback(Callback callback) { - synchronized (mCallbacks) { - mCallbacks.add(callback); - } - } - - void unregisterCallback(Callback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } - } - - private void dispatchAttributesChanged() { - synchronized (mCallbacks) { - for (Callback callback : mCallbacks) { - callback.onDeviceAttributesChanged(); - } - } - } - - @Override - public String toString() { - return mDevice.toString(); - } - - @Override - public boolean equals(Object o) { - if ((o == null) || !(o instanceof CachedBluetoothDevice)) { - return false; - } - return mDevice.equals(((CachedBluetoothDevice) o).mDevice); - } - - @Override - public int hashCode() { - return mDevice.getAddress().hashCode(); - } - - // This comparison uses non-final fields so the sort order may change - // when device attributes change (such as bonding state). Settings - // will completely refresh the device list when this happens. - public int compareTo(CachedBluetoothDevice another) { - // Connected above not connected - int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0); - if (comparison != 0) return comparison; - - // Paired above not paired - comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) - - (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0); - if (comparison != 0) return comparison; - - // Visible above not visible - comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0); - if (comparison != 0) return comparison; - - // Stronger signal above weaker signal - comparison = another.mRssi - mRssi; - if (comparison != 0) return comparison; - - // Fallback on name - return mName.compareTo(another.mName); - } - - public interface Callback { - void onDeviceAttributesChanged(); - } - - int getPhonebookPermissionChoice() { - int permission = mDevice.getPhonebookAccessPermission(); - if (permission == BluetoothDevice.ACCESS_ALLOWED) { - return ACCESS_ALLOWED; - } else if (permission == BluetoothDevice.ACCESS_REJECTED) { - return ACCESS_REJECTED; - } - return ACCESS_UNKNOWN; - } - - void setPhonebookPermissionChoice(int permissionChoice) { - int permission = BluetoothDevice.ACCESS_UNKNOWN; - if (permissionChoice == ACCESS_ALLOWED) { - permission = BluetoothDevice.ACCESS_ALLOWED; - } else if (permissionChoice == ACCESS_REJECTED) { - permission = BluetoothDevice.ACCESS_REJECTED; - } - mDevice.setPhonebookAccessPermission(permission); - } - - // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth - // app's shared preferences). - private void migratePhonebookPermissionChoice() { - SharedPreferences preferences = mContext.getSharedPreferences( - "bluetooth_phonebook_permission", Context.MODE_PRIVATE); - if (!preferences.contains(mDevice.getAddress())) { - return; - } - - if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) { - int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN); - if (oldPermission == ACCESS_ALLOWED) { - mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); - } else if (oldPermission == ACCESS_REJECTED) { - mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED); - } - } - - SharedPreferences.Editor editor = preferences.edit(); - editor.remove(mDevice.getAddress()); - editor.commit(); - } - - int getMessagePermissionChoice() { - int permission = mDevice.getMessageAccessPermission(); - if (permission == BluetoothDevice.ACCESS_ALLOWED) { - return ACCESS_ALLOWED; - } else if (permission == BluetoothDevice.ACCESS_REJECTED) { - return ACCESS_REJECTED; - } - return ACCESS_UNKNOWN; - } - - void setMessagePermissionChoice(int permissionChoice) { - int permission = BluetoothDevice.ACCESS_UNKNOWN; - if (permissionChoice == ACCESS_ALLOWED) { - permission = BluetoothDevice.ACCESS_ALLOWED; - } else if (permissionChoice == ACCESS_REJECTED) { - permission = BluetoothDevice.ACCESS_REJECTED; - } - mDevice.setMessageAccessPermission(permission); - } - - // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth - // app's shared preferences). - private void migrateMessagePermissionChoice() { - SharedPreferences preferences = mContext.getSharedPreferences( - "bluetooth_message_permission", Context.MODE_PRIVATE); - if (!preferences.contains(mDevice.getAddress())) { - return; - } - - if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) { - int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN); - if (oldPermission == ACCESS_ALLOWED) { - mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); - } else if (oldPermission == ACCESS_REJECTED) { - mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED); - } - } - - SharedPreferences.Editor editor = preferences.edit(); - editor.remove(mDevice.getAddress()); - editor.commit(); - } - - /** - * @return Whether this rejection should persist. - */ - boolean checkAndIncreaseMessageRejectionCount() { - if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) { - mMessageRejectionCount++; - saveMessageRejectionCount(); - } - return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST; - } - - private void fetchMessageRejectionCount() { - SharedPreferences preference = mContext.getSharedPreferences( - MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE); - mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0); - } - - private void saveMessageRejectionCount() { - SharedPreferences.Editor editor = mContext.getSharedPreferences( - MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit(); - if (mMessageRejectionCount == 0) { - editor.remove(mDevice.getAddress()); - } else { - editor.putInt(mDevice.getAddress(), mMessageRejectionCount); - } - editor.commit(); - } - - private void processPhonebookAccess() { - if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return; - - ParcelUuid[] uuids = mDevice.getUuids(); - if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) { - // The pairing dialog now warns of phone-book access for paired devices. - // No separate prompt is displayed after pairing. - setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED); - } - } -} diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java deleted file mode 100755 index 2b0e7f1..0000000 --- a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.content.Context; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices. - */ -final class CachedBluetoothDeviceManager { - private static final String TAG = "CachedBluetoothDeviceManager"; - private static final boolean DEBUG = Utils.D; - - private Context mContext; - private final List<CachedBluetoothDevice> mCachedDevices = - new ArrayList<CachedBluetoothDevice>(); - - CachedBluetoothDeviceManager(Context context) { - mContext = context; - } - - public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() { - return new ArrayList<CachedBluetoothDevice>(mCachedDevices); - } - - public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) { - cachedDevice.setVisible(false); - return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE; - } - - public void onDeviceNameUpdated(BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = findDevice(device); - if (cachedDevice != null) { - cachedDevice.refreshName(); - } - } - - /** - * Search for existing {@link CachedBluetoothDevice} or return null - * if this device isn't in the cache. Use {@link #addDevice} - * to create and return a new {@link CachedBluetoothDevice} for - * a newly discovered {@link BluetoothDevice}. - * - * @param device the address of the Bluetooth device - * @return the cached device object for this device, or null if it has - * not been previously seen - */ - CachedBluetoothDevice findDevice(BluetoothDevice device) { - for (CachedBluetoothDevice cachedDevice : mCachedDevices) { - if (cachedDevice.getDevice().equals(device)) { - return cachedDevice; - } - } - return null; - } - - /** - * Create and return a new {@link CachedBluetoothDevice}. This assumes - * that {@link #findDevice} has already been called and returned null. - * @param device the address of the new Bluetooth device - * @return the newly created CachedBluetoothDevice object - */ - CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter, - LocalBluetoothProfileManager profileManager, - BluetoothDevice device) { - CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter, - profileManager, device); - synchronized (mCachedDevices) { - mCachedDevices.add(newDevice); - } - return newDevice; - } - - /** - * Attempts to get the name of a remote device, otherwise returns the address. - * - * @param device The remote device. - * @return The name, or if unavailable, the address. - */ - public String getName(BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = findDevice(device); - if (cachedDevice != null) { - return cachedDevice.getName(); - } - - String name = device.getAliasName(); - if (name != null) { - return name; - } - - return device.getAddress(); - } - - public synchronized void clearNonBondedDevices() { - for (int i = mCachedDevices.size() - 1; i >= 0; i--) { - CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); - if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) { - mCachedDevices.remove(i); - } - } - } - - public synchronized void onScanningStateChanged(boolean started) { - if (!started) return; - - // If starting a new scan, clear old visibility - // Iterate in reverse order since devices may be removed. - for (int i = mCachedDevices.size() - 1; i >= 0; i--) { - CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); - cachedDevice.setVisible(false); - } - } - - public synchronized void onBtClassChanged(BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = findDevice(device); - if (cachedDevice != null) { - cachedDevice.refreshBtClass(); - } - } - - public synchronized void onUuidChanged(BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = findDevice(device); - if (cachedDevice != null) { - cachedDevice.onUuidChanged(); - } - } - - public synchronized void onBluetoothStateChanged(int bluetoothState) { - // When Bluetooth is turning off, we need to clear the non-bonded devices - // Otherwise, they end up showing up on the next BT enable - if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) { - for (int i = mCachedDevices.size() - 1; i >= 0; i--) { - CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); - if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) { - cachedDevice.setVisible(false); - mCachedDevices.remove(i); - } else { - // For bonded devices, we need to clear the connection status so that - // when BT is enabled next time, device connection status shall be retrieved - // by making a binder call. - cachedDevice.clearProfileConnectionState(); - } - } - } - } - private void log(String msg) { - if (DEBUG) { - Log.d(TAG, msg); - } - } -} diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java index e7208b5..b2a703d 100644 --- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java @@ -16,8 +16,12 @@ package com.android.settings.bluetooth; +import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceCategory; @@ -26,6 +30,11 @@ import android.preference.PreferenceScreen; import android.util.Log; import com.android.settings.RestrictedSettingsFragment; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.BluetoothDeviceFilter; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.Collection; import java.util.WeakHashMap; @@ -74,7 +83,7 @@ public abstract class DeviceListPreferenceFragment extends public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mLocalManager = LocalBluetoothManager.getInstance(getActivity()); + mLocalManager = Utils.getLocalBtManager(getActivity()); if (mLocalManager == null) { Log.e(TAG, "Bluetooth is not supported on this device"); return; @@ -164,7 +173,7 @@ public abstract class DeviceListPreferenceFragment extends if (mFilter.matches(cachedDevice.getDevice())) { createDevicePreference(cachedDevice); } - } + } void createDevicePreference(CachedBluetoothDevice cachedDevice) { if (mDeviceListGroup == null) { diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java index 354d03c..809ca96 100644 --- a/src/com/android/settings/bluetooth/DevicePickerFragment.java +++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java @@ -17,6 +17,7 @@ package com.android.settings.bluetooth; import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; + import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevicePicker; @@ -29,6 +30,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import com.android.settings.R; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; /** * BluetoothSettings is the Settings screen for Bluetooth configuration and diff --git a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java index 0109e35..89287ab 100755 --- a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java +++ b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java @@ -42,6 +42,13 @@ import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.Index; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfile; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.bluetooth.MapProfile; +import com.android.settingslib.bluetooth.PbapServerProfile; import java.util.HashMap; @@ -80,7 +87,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER); mProfileContainer.setLayoutResource(R.layout.bluetooth_preference_category); - mManager = LocalBluetoothManager.getInstance(getActivity()); + mManager = Utils.getLocalBtManager(getActivity()); CachedBluetoothDeviceManager deviceManager = mManager.getCachedDeviceManager(); mProfileManager = mManager.getProfileManager(); diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java index c9a18a3..c4f6485 100644 --- a/src/com/android/settings/bluetooth/DockService.java +++ b/src/com/android/settings/bluetooth/DockService.java @@ -16,9 +16,6 @@ package com.android.settings.bluetooth; -import com.android.settings.R; -import com.android.settings.bluetooth.LocalBluetoothProfileManager.ServiceListener; - import android.app.AlertDialog; import android.app.Notification; import android.app.Service; @@ -27,6 +24,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; @@ -44,6 +42,16 @@ import android.view.WindowManager; import android.widget.CheckBox; import android.widget.CompoundButton; +import com.android.settings.R; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfile; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager.ServiceListener; + import java.util.Collection; import java.util.List; import java.util.Set; @@ -126,7 +134,7 @@ public final class DockService extends Service implements ServiceListener { public void onCreate() { if (DEBUG) Log.d(TAG, "onCreate"); - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); + LocalBluetoothManager manager = Utils.getLocalBtManager(this); if (manager == null) { Log.e(TAG, "Can't get LocalBluetoothManager: exiting"); return; @@ -918,4 +926,56 @@ public final class DockService extends Service implements ServiceListener { public void onServiceDisconnected() { // FIXME: shouldn't I do something on service disconnected too? } + + public static class DockBluetoothCallback implements BluetoothCallback { + private final Context mContext; + + public DockBluetoothCallback(Context context) { + mContext = context; + } + + public void onBluetoothStateChanged(int bluetoothState) { } + public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { } + public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { } + + @Override + public void onScanningStateChanged(boolean started) { + // TODO: Find a more unified place for a persistent BluetoothCallback to live + // as this is not exactly dock related. + LocalBluetoothPreferences.persistDiscoveringTimestamp(mContext); + } + + @Override + public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { + BluetoothDevice device = cachedDevice.getDevice(); + if (bondState == BluetoothDevice.BOND_NONE) { + if (device.isBluetoothDock()) { + // After a dock is unpaired, we will forget the settings + LocalBluetoothPreferences + .removeDockAutoConnectSetting(mContext, device.getAddress()); + + // if the device is undocked, remove it from the list as well + if (!device.getAddress().equals(getDockedDeviceAddress(mContext))) { + cachedDevice.setVisible(false); + } + } + } + } + + // This can't be called from a broadcast receiver where the filter is set in the Manifest. + private static String getDockedDeviceAddress(Context context) { + // This works only because these broadcast intents are "sticky" + Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + if (i != null) { + int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { + BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (device != null) { + return device.getAddress(); + } + } + } + return null; + } + } } diff --git a/src/com/android/settings/bluetooth/HeadsetProfile.java b/src/com/android/settings/bluetooth/HeadsetProfile.java deleted file mode 100755 index 45b81ab..0000000 --- a/src/com/android/settings/bluetooth/HeadsetProfile.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.os.ParcelUuid; -import android.util.Log; - -import com.android.settings.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * HeadsetProfile handles Bluetooth HFP and Headset profiles. - */ -final class HeadsetProfile implements LocalBluetoothProfile { - private static final String TAG = "HeadsetProfile"; - private static boolean V = true; - - private BluetoothHeadset mService; - private boolean mIsProfileReady; - - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - private final LocalBluetoothProfileManager mProfileManager; - - static final ParcelUuid[] UUIDS = { - BluetoothUuid.HSP, - BluetoothUuid.Handsfree, - }; - - static final String NAME = "HEADSET"; - - // Order of this profile in device profiles list - private static final int ORDINAL = 0; - - // These callbacks run on the main thread. - private final class HeadsetServiceListener - implements BluetoothProfile.ServiceListener { - - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothHeadset) proxy; - // We just bound to the service, so refresh the UI for any connected HFP devices. - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - while (!deviceList.isEmpty()) { - BluetoothDevice nextDevice = deviceList.remove(0); - CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); - // we may add a new device here, but generally this should not happen - if (device == null) { - Log.w(TAG, "HeadsetProfile found new device: " + nextDevice); - device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); - } - device.onProfileStateChanged(HeadsetProfile.this, - BluetoothProfile.STATE_CONNECTED); - device.refresh(); - } - - mProfileManager.callServiceConnectedListeners(); - mIsProfileReady=true; - } - - public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mProfileManager.callServiceDisconnectedListeners(); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - return mIsProfileReady; - } - - HeadsetProfile(Context context, LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, - LocalBluetoothProfileManager profileManager) { - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mProfileManager = profileManager; - mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(), - BluetoothProfile.HEADSET); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return true; - } - - public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> sinks = mService.getConnectedDevices(); - if (sinks != null) { - for (BluetoothDevice sink : sinks) { - Log.d(TAG,"Not disconnecting device = " + sink); - } - } - return mService.connect(device); - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - if (!deviceList.isEmpty()) { - for (BluetoothDevice dev : deviceList) { - if (dev.equals(device)) { - if (V) Log.d(TAG,"Downgrade priority as user" + - "is disconnecting the headset"); - // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - return mService.disconnect(device); - } - } - } - return false; - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.STATE_DISCONNECTED; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - if (!deviceList.isEmpty()){ - for (BluetoothDevice dev : deviceList) { - if (dev.equals(device)) { - return mService.getConnectionState(device); - } - } - } - return BluetoothProfile.STATE_DISCONNECTED; - } - - public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; - } - - public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; - if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); - } - } - - public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); - return mService.getDevicesMatchingConnectionStates( - new int[] {BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTING}); - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - return R.string.bluetooth_profile_headset; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - int state = getConnectionStatus(device); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return R.string.bluetooth_headset_profile_summary_use_for; - - case BluetoothProfile.STATE_CONNECTED: - return R.string.bluetooth_headset_profile_summary_connected; - - default: - return Utils.getConnectionStateSummary(state); - } - } - - public int getDrawableResource(BluetoothClass btClass) { - return R.drawable.ic_bt_headset_hfp; - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET, - mService); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up HID proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/HidProfile.java b/src/com/android/settings/bluetooth/HidProfile.java deleted file mode 100755 index 91e715d..0000000 --- a/src/com/android/settings/bluetooth/HidProfile.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothInputDevice; -import android.bluetooth.BluetoothProfile; -import android.content.Context; -import android.util.Log; - -import com.android.settings.R; - -import java.util.List; - -/** - * HidProfile handles Bluetooth HID profile. - */ -final class HidProfile implements LocalBluetoothProfile { - private static final String TAG = "HidProfile"; - private static boolean V = true; - - private BluetoothInputDevice mService; - private boolean mIsProfileReady; - - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - private final LocalBluetoothProfileManager mProfileManager; - - static final String NAME = "HID"; - - // Order of this profile in device profiles list - private static final int ORDINAL = 3; - - // These callbacks run on the main thread. - private final class InputDeviceServiceListener - implements BluetoothProfile.ServiceListener { - - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothInputDevice) proxy; - // We just bound to the service, so refresh the UI for any connected HID devices. - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - while (!deviceList.isEmpty()) { - BluetoothDevice nextDevice = deviceList.remove(0); - CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); - // we may add a new device here, but generally this should not happen - if (device == null) { - Log.w(TAG, "HidProfile found new device: " + nextDevice); - device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); - } - device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED); - device.refresh(); - } - mIsProfileReady=true; - } - - public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - return mIsProfileReady; - } - - HidProfile(Context context, LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, - LocalBluetoothProfileManager profileManager) { - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mProfileManager = profileManager; - adapter.getProfileProxy(context, new InputDeviceServiceListener(), - BluetoothProfile.INPUT_DEVICE); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return true; - } - - public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - return mService.connect(device); - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - return mService.disconnect(device); - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) { - return BluetoothProfile.STATE_DISCONNECTED; - } - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - - return !deviceList.isEmpty() && deviceList.get(0).equals(device) - ? mService.getConnectionState(device) - : BluetoothProfile.STATE_DISCONNECTED; - } - - public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; - } - - public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; - if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); - } - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - // TODO: distinguish between keyboard and mouse? - return R.string.bluetooth_profile_hid; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - int state = getConnectionStatus(device); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return R.string.bluetooth_hid_profile_summary_use_for; - - case BluetoothProfile.STATE_CONNECTED: - return R.string.bluetooth_hid_profile_summary_connected; - - default: - return Utils.getConnectionStateSummary(state); - } - } - - public int getDrawableResource(BluetoothClass btClass) { - if (btClass == null) { - return R.drawable.ic_lockscreen_ime; - } - return getHidClassDrawable(btClass); - } - - static int getHidClassDrawable(BluetoothClass btClass) { - switch (btClass.getDeviceClass()) { - case BluetoothClass.Device.PERIPHERAL_KEYBOARD: - case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING: - return R.drawable.ic_lockscreen_ime; - case BluetoothClass.Device.PERIPHERAL_POINTING: - return R.drawable.ic_bt_pointing_hid; - default: - return R.drawable.ic_bt_misc_hid; - } - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE, - mService); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up HID proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java deleted file mode 100644 index 013171c..0000000 --- a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; -import android.content.Context; -import android.os.ParcelUuid; -import android.util.Log; - -import java.util.Set; - -/** - * LocalBluetoothAdapter provides an interface between the Settings app - * and the functionality of the local {@link BluetoothAdapter}, specifically - * those related to state transitions of the adapter itself. - * - * <p>Connection and bonding state changes affecting specific devices - * are handled by {@link CachedBluetoothDeviceManager}, - * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}. - */ -public final class LocalBluetoothAdapter { - private static final String TAG = "LocalBluetoothAdapter"; - - /** This class does not allow direct access to the BluetoothAdapter. */ - private final BluetoothAdapter mAdapter; - - private LocalBluetoothProfileManager mProfileManager; - - private static LocalBluetoothAdapter sInstance; - - private int mState = BluetoothAdapter.ERROR; - - private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins - - private long mLastScan; - - private LocalBluetoothAdapter(BluetoothAdapter adapter) { - mAdapter = adapter; - } - - void setProfileManager(LocalBluetoothProfileManager manager) { - mProfileManager = manager; - } - - /** - * Get the singleton instance of the LocalBluetoothAdapter. If this device - * doesn't support Bluetooth, then null will be returned. Callers must be - * prepared to handle a null return value. - * @return the LocalBluetoothAdapter object, or null if not supported - */ - static synchronized LocalBluetoothAdapter getInstance() { - if (sInstance == null) { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - sInstance = new LocalBluetoothAdapter(adapter); - } - } - - return sInstance; - } - - // Pass-through BluetoothAdapter methods that we can intercept if necessary - - void cancelDiscovery() { - mAdapter.cancelDiscovery(); - } - - boolean enable() { - return mAdapter.enable(); - } - - boolean disable() { - return mAdapter.disable(); - } - - void getProfileProxy(Context context, - BluetoothProfile.ServiceListener listener, int profile) { - mAdapter.getProfileProxy(context, listener, profile); - } - - Set<BluetoothDevice> getBondedDevices() { - return mAdapter.getBondedDevices(); - } - - String getName() { - return mAdapter.getName(); - } - - int getScanMode() { - return mAdapter.getScanMode(); - } - - int getState() { - return mAdapter.getState(); - } - - ParcelUuid[] getUuids() { - return mAdapter.getUuids(); - } - - boolean isDiscovering() { - return mAdapter.isDiscovering(); - } - - boolean isEnabled() { - return mAdapter.isEnabled(); - } - - void setDiscoverableTimeout(int timeout) { - mAdapter.setDiscoverableTimeout(timeout); - } - - void setName(String name) { - mAdapter.setName(name); - } - - void setScanMode(int mode) { - mAdapter.setScanMode(mode); - } - - boolean setScanMode(int mode, int duration) { - return mAdapter.setScanMode(mode, duration); - } - - void startScanning(boolean force) { - // Only start if we're not already scanning - if (!mAdapter.isDiscovering()) { - if (!force) { - // Don't scan more than frequently than SCAN_EXPIRATION_MS, - // unless forced - if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) { - return; - } - - // If we are playing music, don't scan unless forced. - A2dpProfile a2dp = mProfileManager.getA2dpProfile(); - if (a2dp != null && a2dp.isA2dpPlaying()) { - return; - } - } - - if (mAdapter.startDiscovery()) { - mLastScan = System.currentTimeMillis(); - } - } - } - - void stopScanning() { - if (mAdapter.isDiscovering()) { - mAdapter.cancelDiscovery(); - } - } - - public synchronized int getBluetoothState() { - // Always sync state, in case it changed while paused - syncBluetoothState(); - return mState; - } - - synchronized void setBluetoothStateInt(int state) { - mState = state; - - if (state == BluetoothAdapter.STATE_ON) { - // if mProfileManager hasn't been constructed yet, it will - // get the adapter UUIDs in its constructor when it is. - if (mProfileManager != null) { - mProfileManager.setBluetoothStateOn(); - } - } - } - - // Returns true if the state changed; false otherwise. - boolean syncBluetoothState() { - int currentState = mAdapter.getState(); - if (currentState != mState) { - setBluetoothStateInt(mAdapter.getState()); - return true; - } - return false; - } - - public void setBluetoothEnabled(boolean enabled) { - boolean success = enabled - ? mAdapter.enable() - : mAdapter.disable(); - - if (success) { - setBluetoothStateInt(enabled - ? BluetoothAdapter.STATE_TURNING_ON - : BluetoothAdapter.STATE_TURNING_OFF); - } else { - if (Utils.V) { - Log.v(TAG, "setBluetoothEnabled call, manager didn't return " + - "success for enabled: " + enabled); - } - - syncBluetoothState(); - } - } -} diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java deleted file mode 100644 index ae8dec2..0000000 --- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.content.Context; -import android.util.Log; - -/** - * LocalBluetoothManager provides a simplified interface on top of a subset of - * the Bluetooth API. Note that {@link #getInstance} will return null - * if there is no Bluetooth adapter on this device, and callers must be - * prepared to handle this case. - */ -public final class LocalBluetoothManager { - private static final String TAG = "LocalBluetoothManager"; - - /** Singleton instance. */ - private static LocalBluetoothManager sInstance; - - private final Context mContext; - - /** If a BT-related activity is in the foreground, this will be it. */ - private Context mForegroundActivity; - - private BluetoothDiscoverableEnabler mDiscoverableEnabler; - - private final LocalBluetoothAdapter mLocalAdapter; - - private final CachedBluetoothDeviceManager mCachedDeviceManager; - - /** The Bluetooth profile manager. */ - private final LocalBluetoothProfileManager mProfileManager; - - /** The broadcast receiver event manager. */ - private final BluetoothEventManager mEventManager; - - public static synchronized LocalBluetoothManager getInstance(Context context) { - if (sInstance == null) { - LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance(); - if (adapter == null) { - return null; - } - // This will be around as long as this process is - Context appContext = context.getApplicationContext(); - sInstance = new LocalBluetoothManager(adapter, appContext); - } - - return sInstance; - } - - public void setDiscoverableEnabler(BluetoothDiscoverableEnabler discoverableEnabler) { - mDiscoverableEnabler = discoverableEnabler; - } - - public BluetoothDiscoverableEnabler getDiscoverableEnabler() { - return mDiscoverableEnabler; - } - - private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) { - mContext = context; - mLocalAdapter = adapter; - - mCachedDeviceManager = new CachedBluetoothDeviceManager(context); - mEventManager = new BluetoothEventManager(mLocalAdapter, - mCachedDeviceManager, context); - mProfileManager = new LocalBluetoothProfileManager(context, - mLocalAdapter, mCachedDeviceManager, mEventManager); - } - - public LocalBluetoothAdapter getBluetoothAdapter() { - return mLocalAdapter; - } - - public Context getContext() { - return mContext; - } - - public Context getForegroundActivity() { - return mForegroundActivity; - } - - boolean isForegroundActivity() { - return mForegroundActivity != null; - } - - synchronized void setForegroundActivity(Context context) { - if (context != null) { - Log.d(TAG, "setting foreground activity to non-null context"); - mForegroundActivity = context; - } else { - if (mForegroundActivity != null) { - Log.d(TAG, "setting foreground activity to null"); - mForegroundActivity = null; - } - } - } - - CachedBluetoothDeviceManager getCachedDeviceManager() { - return mCachedDeviceManager; - } - - BluetoothEventManager getEventManager() { - return mEventManager; - } - - LocalBluetoothProfileManager getProfileManager() { - return mProfileManager; - } -} diff --git a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java index f00b801..9f2553f 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java @@ -22,6 +22,9 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.util.Log; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + /** * LocalBluetoothPreferences provides an interface to the preferences * related to Bluetooth. @@ -60,7 +63,7 @@ final class LocalBluetoothPreferences { static boolean shouldShowDialogInForeground(Context context, String deviceAddress) { - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context); + LocalBluetoothManager manager = Utils.getLocalBtManager(context); if (manager == null) { if(DEBUG) Log.v(TAG, "manager == null - do not show dialog."); return false; diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfile.java b/src/com/android/settings/bluetooth/LocalBluetoothProfile.java deleted file mode 100755 index 8c0de95..0000000 --- a/src/com/android/settings/bluetooth/LocalBluetoothProfile.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; - -/** - * LocalBluetoothProfile is an interface defining the basic - * functionality related to a Bluetooth profile. - */ -interface LocalBluetoothProfile { - - /** - * Returns true if the user can initiate a connection, false otherwise. - */ - boolean isConnectable(); - - /** - * Returns true if the user can enable auto connection for this profile. - */ - boolean isAutoConnectable(); - - boolean connect(BluetoothDevice device); - - boolean disconnect(BluetoothDevice device); - - int getConnectionStatus(BluetoothDevice device); - - boolean isPreferred(BluetoothDevice device); - - int getPreferred(BluetoothDevice device); - - void setPreferred(BluetoothDevice device, boolean preferred); - - boolean isProfileReady(); - - /** Display order for device profile settings. */ - int getOrdinal(); - - /** - * Returns the string resource ID for the localized name for this profile. - * @param device the Bluetooth device (to distinguish between PAN roles) - */ - int getNameResource(BluetoothDevice device); - - /** - * Returns the string resource ID for the summary text for this profile - * for the specified device, e.g. "Use for media audio" or - * "Connected to media audio". - * @param device the device to query for profile connection status - * @return a string resource ID for the profile summary text - */ - int getSummaryResourceForDevice(BluetoothDevice device); - - int getDrawableResource(BluetoothClass btClass); -} diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java deleted file mode 100644 index 2a6a759..0000000 --- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothMap; -import android.bluetooth.BluetoothInputDevice; -import android.bluetooth.BluetoothPan; -import android.bluetooth.BluetoothPbap; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.content.Intent; -import android.os.ParcelUuid; -import android.util.Log; -import android.os.Handler; -import android.os.Message; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.List; - -/** - * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile - * objects for the available Bluetooth profiles. - */ -final class LocalBluetoothProfileManager { - private static final String TAG = "LocalBluetoothProfileManager"; - private static final boolean DEBUG = Utils.D; - /** Singleton instance. */ - private static LocalBluetoothProfileManager sInstance; - - /** - * An interface for notifying BluetoothHeadset IPC clients when they have - * been connected to the BluetoothHeadset service. - * Only used by {@link DockService}. - */ - 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. - */ - 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. - */ - void onServiceDisconnected(); - } - - private final Context mContext; - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - private final BluetoothEventManager mEventManager; - - private A2dpProfile mA2dpProfile; - private HeadsetProfile mHeadsetProfile; - private MapProfile mMapProfile; - private final HidProfile mHidProfile; - private OppProfile mOppProfile; - private final PanProfile mPanProfile; - private final PbapServerProfile mPbapProfile; - - /** - * Mapping from profile name, e.g. "HEADSET" to profile object. - */ - private final Map<String, LocalBluetoothProfile> - mProfileNameMap = new HashMap<String, LocalBluetoothProfile>(); - - LocalBluetoothProfileManager(Context context, - LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, - BluetoothEventManager eventManager) { - mContext = context; - - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mEventManager = eventManager; - // pass this reference to adapter and event manager (circular dependency) - mLocalAdapter.setProfileManager(this); - mEventManager.setProfileManager(this); - - ParcelUuid[] uuids = adapter.getUuids(); - - // uuids may be null if Bluetooth is turned off - if (uuids != null) { - updateLocalProfiles(uuids); - } - - // Always add HID and PAN profiles - mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this); - addProfile(mHidProfile, HidProfile.NAME, - BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); - - mPanProfile = new PanProfile(context); - addPanProfile(mPanProfile, PanProfile.NAME, - BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); - - if(DEBUG) Log.d(TAG, "Adding local MAP profile"); - mMapProfile = new MapProfile(mContext, mLocalAdapter, - mDeviceManager, this); - addProfile(mMapProfile, MapProfile.NAME, - BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); - - //Create PBAP server profile, but do not add it to list of profiles - // as we do not need to monitor the profile as part of profile list - mPbapProfile = new PbapServerProfile(context); - - if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete"); - } - - /** - * Initialize or update the local profile objects. If a UUID was previously - * present but has been removed, we print a warning but don't remove the - * profile object as it might be referenced elsewhere, or the UUID might - * come back and we don't want multiple copies of the profile objects. - * @param uuids - */ - void updateLocalProfiles(ParcelUuid[] uuids) { - // A2DP - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) { - if (mA2dpProfile == null) { - if(DEBUG) Log.d(TAG, "Adding local A2DP profile"); - mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this); - addProfile(mA2dpProfile, A2dpProfile.NAME, - BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); - } - } else if (mA2dpProfile != null) { - Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing."); - } - - // Headset / Handsfree - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) || - BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) { - if (mHeadsetProfile == null) { - if (DEBUG) Log.d(TAG, "Adding local HEADSET profile"); - mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter, - mDeviceManager, this); - addProfile(mHeadsetProfile, HeadsetProfile.NAME, - BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); - } - } else if (mHeadsetProfile != null) { - Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing."); - } - - // OPP - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) { - if (mOppProfile == null) { - if(DEBUG) Log.d(TAG, "Adding local OPP profile"); - mOppProfile = new OppProfile(); - // Note: no event handler for OPP, only name map. - mProfileNameMap.put(OppProfile.NAME, mOppProfile); - } - } else if (mOppProfile != null) { - Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); - } - mEventManager.registerProfileIntentReceiver(); - - // There is no local SDP record for HID and Settings app doesn't control PBAP - } - - private final Collection<ServiceListener> mServiceListeners = - new ArrayList<ServiceListener>(); - - private void addProfile(LocalBluetoothProfile profile, - String profileName, String stateChangedAction) { - mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile)); - mProfileNameMap.put(profileName, profile); - } - - private void addPanProfile(LocalBluetoothProfile profile, - String profileName, String stateChangedAction) { - mEventManager.addProfileHandler(stateChangedAction, - new PanStateChangedHandler(profile)); - mProfileNameMap.put(profileName, profile); - } - - LocalBluetoothProfile getProfileByName(String name) { - return mProfileNameMap.get(name); - } - - // Called from LocalBluetoothAdapter when state changes to ON - void setBluetoothStateOn() { - ParcelUuid[] uuids = mLocalAdapter.getUuids(); - if (uuids != null) { - updateLocalProfiles(uuids); - } - mEventManager.readPairedDevices(); - } - - /** - * Generic handler for connection state change events for the specified profile. - */ - private class StateChangedHandler implements BluetoothEventManager.Handler { - final LocalBluetoothProfile mProfile; - - StateChangedHandler(LocalBluetoothProfile profile) { - mProfile = profile; - } - - public void onReceive(Context context, Intent intent, BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - Log.w(TAG, "StateChangedHandler found new device: " + device); - cachedDevice = mDeviceManager.addDevice(mLocalAdapter, - LocalBluetoothProfileManager.this, device); - } - int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0); - int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0); - if (newState == BluetoothProfile.STATE_DISCONNECTED && - oldState == BluetoothProfile.STATE_CONNECTING) { - Log.i(TAG, "Failed to connect " + mProfile + " device"); - } - - cachedDevice.onProfileStateChanged(mProfile, newState); - cachedDevice.refresh(); - } - } - - /** State change handler for NAP and PANU profiles. */ - private class PanStateChangedHandler extends StateChangedHandler { - - PanStateChangedHandler(LocalBluetoothProfile profile) { - super(profile); - } - - @Override - public void onReceive(Context context, Intent intent, BluetoothDevice device) { - PanProfile panProfile = (PanProfile) mProfile; - int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0); - panProfile.setLocalRole(device, role); - super.onReceive(context, intent, device); - } - } - - // called from DockService - void addServiceListener(ServiceListener l) { - mServiceListeners.add(l); - } - - // called from DockService - void removeServiceListener(ServiceListener l) { - mServiceListeners.remove(l); - } - - // not synchronized: use only from UI thread! (TODO: verify) - void callServiceConnectedListeners() { - for (ServiceListener l : mServiceListeners) { - l.onServiceConnected(); - } - } - - // not synchronized: use only from UI thread! (TODO: verify) - void callServiceDisconnectedListeners() { - for (ServiceListener listener : mServiceListeners) { - listener.onServiceDisconnected(); - } - } - - // This is called by DockService, so check Headset and A2DP. - public synchronized 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. - LocalBluetoothProfile profile = mHeadsetProfile; - if (profile != null) { - return profile.isProfileReady(); - } - profile = mA2dpProfile; - if (profile != null) { - return profile.isProfileReady(); - } - return false; - } - - A2dpProfile getA2dpProfile() { - return mA2dpProfile; - } - - HeadsetProfile getHeadsetProfile() { - return mHeadsetProfile; - } - - PbapServerProfile getPbapProfile(){ - return mPbapProfile; - } - - MapProfile getMapProfile(){ - return mMapProfile; - } - - /** - * Fill in a list of LocalBluetoothProfile objects that are supported by - * the local device and the remote device. - * - * @param uuids of the remote device - * @param localUuids UUIDs of the local device - * @param profiles The list of profiles to fill - * @param removedProfiles list of profiles that were removed - */ - synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids, - Collection<LocalBluetoothProfile> profiles, - Collection<LocalBluetoothProfile> removedProfiles, - boolean isPanNapConnected, BluetoothDevice device) { - // Copy previous profile list into removedProfiles - removedProfiles.clear(); - removedProfiles.addAll(profiles); - profiles.clear(); - - if (uuids == null) { - return; - } - - if (mHeadsetProfile != null) { - if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) && - BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) || - (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) && - BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) { - profiles.add(mHeadsetProfile); - removedProfiles.remove(mHeadsetProfile); - } - } - - if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) && - mA2dpProfile != null) { - profiles.add(mA2dpProfile); - removedProfiles.remove(mA2dpProfile); - } - - if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) && - mOppProfile != null) { - profiles.add(mOppProfile); - removedProfiles.remove(mOppProfile); - } - - if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) || - BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) && - mHidProfile != null) { - profiles.add(mHidProfile); - removedProfiles.remove(mHidProfile); - } - - if(isPanNapConnected) - if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists."); - if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) && - mPanProfile != null) || isPanNapConnected) { - profiles.add(mPanProfile); - removedProfiles.remove(mPanProfile); - } - - if ((mMapProfile != null) && - (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) { - profiles.add(mMapProfile); - removedProfiles.remove(mMapProfile); - mMapProfile.setPreferred(device, true); - } - } - -} diff --git a/src/com/android/settings/bluetooth/MapProfile.java b/src/com/android/settings/bluetooth/MapProfile.java deleted file mode 100644 index f47e24f..0000000 --- a/src/com/android/settings/bluetooth/MapProfile.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothMap; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.os.ParcelUuid; -import android.util.Log; - -import com.android.settings.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * MapProfile handles Bluetooth MAP profile. - */ -final class MapProfile implements LocalBluetoothProfile { - private static final String TAG = "MapProfile"; - private static boolean V = true; - - private BluetoothMap mService; - private boolean mIsProfileReady; - - private final LocalBluetoothAdapter mLocalAdapter; - private final CachedBluetoothDeviceManager mDeviceManager; - private final LocalBluetoothProfileManager mProfileManager; - - static final ParcelUuid[] UUIDS = { - BluetoothUuid.MAP, - BluetoothUuid.MNS, - BluetoothUuid.MAS, - }; - - static final String NAME = "MAP"; - - // Order of this profile in device profiles list - - // These callbacks run on the main thread. - private final class MapServiceListener - implements BluetoothProfile.ServiceListener { - - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothMap) proxy; - // We just bound to the service, so refresh the UI for any connected MAP devices. - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - while (!deviceList.isEmpty()) { - BluetoothDevice nextDevice = deviceList.remove(0); - CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); - // we may add a new device here, but generally this should not happen - if (device == null) { - Log.w(TAG, "MapProfile found new device: " + nextDevice); - device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); - } - device.onProfileStateChanged(MapProfile.this, - BluetoothProfile.STATE_CONNECTED); - device.refresh(); - } - - mProfileManager.callServiceConnectedListeners(); - mIsProfileReady=true; - } - - public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mProfileManager.callServiceDisconnectedListeners(); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady); - return mIsProfileReady; - } - - MapProfile(Context context, LocalBluetoothAdapter adapter, - CachedBluetoothDeviceManager deviceManager, - LocalBluetoothProfileManager profileManager) { - mLocalAdapter = adapter; - mDeviceManager = deviceManager; - mProfileManager = profileManager; - mLocalAdapter.getProfileProxy(context, new MapServiceListener(), - BluetoothProfile.MAP); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return true; - } - - public boolean connect(BluetoothDevice device) { - if(V)Log.d(TAG,"connect() - should not get called"); - return false; // MAP never connects out - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) { - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - return mService.disconnect(device); - } else { - return false; - } - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.STATE_DISCONNECTED; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device)); - - return !deviceList.isEmpty() && deviceList.get(0).equals(device) - ? mService.getConnectionState(device) - : BluetoothProfile.STATE_DISCONNECTED; - } - - public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; - } - - public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; - if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); - } - } - - public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); - return mService.getDevicesMatchingConnectionStates( - new int[] {BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTING}); - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return BluetoothProfile.MAP; - } - - public int getNameResource(BluetoothDevice device) { - return R.string.bluetooth_profile_map; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - int state = getConnectionStatus(device); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return R.string.bluetooth_map_profile_summary_use_for; - - case BluetoothProfile.STATE_CONNECTED: - return R.string.bluetooth_map_profile_summary_connected; - - default: - return Utils.getConnectionStateSummary(state); - } - } - - public int getDrawableResource(BluetoothClass btClass) { - return R.drawable.ic_bt_cellphone; - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP, - mService); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up MAP proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/OppProfile.java b/src/com/android/settings/bluetooth/OppProfile.java deleted file mode 100755 index 7ee2ad1..0000000 --- a/src/com/android/settings/bluetooth/OppProfile.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import com.android.settings.R; - -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; - -/** - * OppProfile handles Bluetooth OPP. - */ -final class OppProfile implements LocalBluetoothProfile { - - static final String NAME = "OPP"; - - // Order of this profile in device profiles list - private static final int ORDINAL = 2; - - public boolean isConnectable() { - return false; - } - - public boolean isAutoConnectable() { - return false; - } - - public boolean connect(BluetoothDevice device) { - return false; - } - - public boolean disconnect(BluetoothDevice device) { - return false; - } - - public int getConnectionStatus(BluetoothDevice device) { - return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP - } - - public boolean isPreferred(BluetoothDevice device) { - return false; - } - - public int getPreferred(BluetoothDevice device) { - return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - } - - public boolean isProfileReady() { - return true; - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - return R.string.bluetooth_profile_opp; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - return 0; // OPP profile not displayed in UI - } - - public int getDrawableResource(BluetoothClass btClass) { - return 0; // no icon for OPP - } -} diff --git a/src/com/android/settings/bluetooth/PanProfile.java b/src/com/android/settings/bluetooth/PanProfile.java deleted file mode 100755 index f6e0691..0000000 --- a/src/com/android/settings/bluetooth/PanProfile.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothPan; -import android.bluetooth.BluetoothProfile; -import android.content.Context; -import android.util.Log; - -import com.android.settings.R; - -import java.util.HashMap; -import java.util.List; - -/** - * PanProfile handles Bluetooth PAN profile (NAP and PANU). - */ -final class PanProfile implements LocalBluetoothProfile { - private static final String TAG = "PanProfile"; - private static boolean V = true; - - private BluetoothPan mService; - private boolean mIsProfileReady; - - // Tethering direction for each device - private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap = - new HashMap<BluetoothDevice, Integer>(); - - static final String NAME = "PAN"; - - // Order of this profile in device profiles list - private static final int ORDINAL = 4; - - // These callbacks run on the main thread. - private final class PanServiceListener - implements BluetoothProfile.ServiceListener { - - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothPan) proxy; - mIsProfileReady=true; - } - - public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - return mIsProfileReady; - } - - PanProfile(Context context) { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - adapter.getProfileProxy(context, new PanServiceListener(), - BluetoothProfile.PAN); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return false; - } - - public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> sinks = mService.getConnectedDevices(); - if (sinks != null) { - for (BluetoothDevice sink : sinks) { - mService.disconnect(sink); - } - } - return mService.connect(device); - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - return mService.disconnect(device); - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) { - return BluetoothProfile.STATE_DISCONNECTED; - } - return mService.getConnectionState(device); - } - - public boolean isPreferred(BluetoothDevice device) { - // return current connection status so profile checkbox is set correctly - return getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED; - } - - public int getPreferred(BluetoothDevice device) { - return -1; - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - // ignore: isPreferred is always true for PAN - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - if (isLocalRoleNap(device)) { - return R.string.bluetooth_profile_pan_nap; - } else { - return R.string.bluetooth_profile_pan; - } - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - int state = getConnectionStatus(device); - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return R.string.bluetooth_pan_profile_summary_use_for; - - case BluetoothProfile.STATE_CONNECTED: - if (isLocalRoleNap(device)) { - return R.string.bluetooth_pan_nap_profile_summary_connected; - } else { - return R.string.bluetooth_pan_user_profile_summary_connected; - } - - default: - return Utils.getConnectionStateSummary(state); - } - } - - public int getDrawableResource(BluetoothClass btClass) { - return R.drawable.ic_bt_network_pan; - } - - // Tethering direction determines UI strings. - void setLocalRole(BluetoothDevice device, int role) { - mDeviceRoleMap.put(device, role); - } - - boolean isLocalRoleNap(BluetoothDevice device) { - if (mDeviceRoleMap.containsKey(device)) { - return mDeviceRoleMap.get(device) == BluetoothPan.LOCAL_NAP_ROLE; - } else { - return false; - } - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up PAN proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/PbapServerProfile.java b/src/com/android/settings/bluetooth/PbapServerProfile.java deleted file mode 100755 index 6e48b12..0000000 --- a/src/com/android/settings/bluetooth/PbapServerProfile.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.settings.bluetooth; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothPbap; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothUuid; -import android.content.Context; -import android.os.ParcelUuid; -import android.util.Log; - -import com.android.settings.R; - -import java.util.HashMap; -import java.util.List; - -/** - * PBAPServer Profile - */ -final class PbapServerProfile implements LocalBluetoothProfile { - private static final String TAG = "PbapServerProfile"; - private static boolean V = true; - - private BluetoothPbap mService; - private boolean mIsProfileReady; - - static final String NAME = "PBAP Server"; - - // Order of this profile in device profiles list - private static final int ORDINAL = 6; - - // The UUIDs indicate that remote device might access pbap server - static final ParcelUuid[] PBAB_CLIENT_UUIDS = { - BluetoothUuid.HSP, - BluetoothUuid.Handsfree, - BluetoothUuid.PBAP_PCE - }; - - // These callbacks run on the main thread. - private final class PbapServiceListener - implements BluetoothPbap.ServiceListener { - - public void onServiceConnected(BluetoothPbap proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); - mService = (BluetoothPbap) proxy; - mIsProfileReady=true; - } - - public void onServiceDisconnected() { - if (V) Log.d(TAG,"Bluetooth service disconnected"); - mIsProfileReady=false; - } - } - - public boolean isProfileReady() { - return mIsProfileReady; - } - - PbapServerProfile(Context context) { - BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener()); - } - - public boolean isConnectable() { - return true; - } - - public boolean isAutoConnectable() { - return false; - } - - public boolean connect(BluetoothDevice device) { - /*Can't connect from server */ - return false; - - } - - public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - return mService.disconnect(); - } - - public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) { - return BluetoothProfile.STATE_DISCONNECTED; - } - if (mService.isConnected(device)) - return BluetoothProfile.STATE_CONNECTED; - else - return BluetoothProfile.STATE_DISCONNECTED; - } - - public boolean isPreferred(BluetoothDevice device) { - return false; - } - - public int getPreferred(BluetoothDevice device) { - return -1; - } - - public void setPreferred(BluetoothDevice device, boolean preferred) { - // ignore: isPreferred is always true for PBAP - } - - public String toString() { - return NAME; - } - - public int getOrdinal() { - return ORDINAL; - } - - public int getNameResource(BluetoothDevice device) { - return R.string.bluetooth_profile_pbap; - } - - public int getSummaryResourceForDevice(BluetoothDevice device) { - return R.string.bluetooth_profile_pbap_summary; - } - - public int getDrawableResource(BluetoothClass btClass) { - return R.drawable.ic_bt_cellphone; - } - - protected void finalize() { - if (V) Log.d(TAG, "finalize()"); - if (mService != null) { - try { - mService.close(); - mService = null; - }catch (Throwable t) { - Log.w(TAG, "Error cleaning up PBAP proxy", t); - } - } - } -} diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java index 9f266a5..9ce332d 100644 --- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java +++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java @@ -16,8 +16,6 @@ package com.android.settings.bluetooth; -import com.android.settings.R; - import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; @@ -30,6 +28,11 @@ import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; +import com.android.settings.R; +import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + /** * RequestPermissionActivity asks the user whether to enable discovery. This is * usually started by an application wanted to start bluetooth and or discovery @@ -275,7 +278,7 @@ public class RequestPermissionActivity extends Activity implements return true; } - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); + LocalBluetoothManager manager = Utils.getLocalBtManager(this); if (manager == null) { Log.e(TAG, "Error: there's a problem starting Bluetooth"); setResult(RESULT_CANCELED); diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java index f108513..87a73a7 100644 --- a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java +++ b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java @@ -19,6 +19,8 @@ package com.android.settings.bluetooth; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.settings.R; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import android.app.Activity; import android.bluetooth.BluetoothAdapter; @@ -146,7 +148,7 @@ public class RequestPermissionHelperActivity extends AlertActivity implements return true; } - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); + LocalBluetoothManager manager = Utils.getLocalBtManager(this); if (manager == null) { Log.e(TAG, "Error: there's a problem starting Bluetooth"); setResult(RESULT_CANCELED); diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java index e9230de..2cbe473 100755 --- a/src/com/android/settings/bluetooth/Utils.java +++ b/src/com/android/settings/bluetooth/Utils.java @@ -17,24 +17,27 @@ package com.android.settings.bluetooth; import android.app.AlertDialog; -import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.DialogInterface; import android.widget.Toast; import com.android.settings.R; +import com.android.settings.bluetooth.DockService.DockBluetoothCallback; import com.android.settings.search.Index; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback; +import com.android.settingslib.bluetooth.Utils.ErrorListener; /** * Utils is a helper class that contains constants for various * Android resource IDs, debug logging flags, and static methods * for creating dialogs. */ -final class Utils { - static final boolean V = false; // verbose logging - static final boolean D = true; // regular logging +public final class Utils { + static final boolean V = com.android.settingslib.bluetooth.Utils.V; // verbose logging + static final boolean D = com.android.settingslib.bluetooth.Utils.D; // regular logging private Utils() { } @@ -91,7 +94,7 @@ final class Utils { static void showError(Context context, String name, int messageResId) { String message = context.getString(messageResId, name); - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context); + LocalBluetoothManager manager = getLocalBtManager(context); Context activity = manager.getForegroundActivity(); if(manager.isForegroundActivity()) { new AlertDialog.Builder(activity) @@ -118,4 +121,25 @@ final class Utils { Index.getInstance(context).updateFromSearchIndexableData(data); } + + public static LocalBluetoothManager getLocalBtManager(Context context) { + return LocalBluetoothManager.getInstance(context, mOnInitCallback); + } + + private static final ErrorListener mErrorListener = new ErrorListener() { + @Override + public void onShowError(Context context, String name, int messageResId) { + showError(context, name, messageResId); + } + }; + + private static final BluetoothManagerCallback mOnInitCallback = new BluetoothManagerCallback() { + @Override + public void onBluetoothManagerInitialized(Context appContext, + LocalBluetoothManager bluetoothManager) { + bluetoothManager.getEventManager().registerCallback( + new DockBluetoothCallback(appContext)); + com.android.settingslib.bluetooth.Utils.setErrorListener(mErrorListener); + } + }; } diff --git a/src/com/android/settings/deviceinfo/UsbSettings.java b/src/com/android/settings/deviceinfo/UsbSettings.java index 42de2fd..c3b3f96 100644 --- a/src/com/android/settings/deviceinfo/UsbSettings.java +++ b/src/com/android/settings/deviceinfo/UsbSettings.java @@ -41,10 +41,12 @@ public class UsbSettings extends SettingsPreferenceFragment { private static final String KEY_MTP = "usb_mtp"; private static final String KEY_PTP = "usb_ptp"; + private static final String KEY_MIDI = "usb_midi"; private UsbManager mUsbManager; private CheckBoxPreference mMtp; private CheckBoxPreference mPtp; + private CheckBoxPreference mMidi; private boolean mUsbAccessoryMode; private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() { @@ -68,6 +70,7 @@ public class UsbSettings extends SettingsPreferenceFragment { mMtp = (CheckBoxPreference)root.findPreference(KEY_MTP); mPtp = (CheckBoxPreference)root.findPreference(KEY_PTP); + mMidi = (CheckBoxPreference)root.findPreference(KEY_MIDI); UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) { @@ -107,27 +110,37 @@ public class UsbSettings extends SettingsPreferenceFragment { if (UsbManager.USB_FUNCTION_MTP.equals(function)) { mMtp.setChecked(true); mPtp.setChecked(false); + mMidi.setChecked(false); } else if (UsbManager.USB_FUNCTION_PTP.equals(function)) { mMtp.setChecked(false); mPtp.setChecked(true); + mMidi.setChecked(false); + } else if (UsbManager.USB_FUNCTION_MIDI.equals(function)) { + mMtp.setChecked(false); + mPtp.setChecked(false); + mMidi.setChecked(true); } else { mMtp.setChecked(false); mPtp.setChecked(false); + mMidi.setChecked(false); } UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) { Log.e(TAG, "USB is locked down"); mMtp.setEnabled(false); mPtp.setEnabled(false); + mMidi.setEnabled(true); } else if (!mUsbAccessoryMode) { //Enable MTP and PTP switch while USB is not in Accessory Mode, otherwise disable it Log.e(TAG, "USB Normal Mode"); mMtp.setEnabled(true); mPtp.setEnabled(true); + mMidi.setEnabled(true); } else { Log.e(TAG, "USB Accessory Mode"); mMtp.setEnabled(false); mPtp.setEnabled(false); + mMidi.setEnabled(false); } } @@ -151,6 +164,8 @@ public class UsbSettings extends SettingsPreferenceFragment { function = UsbManager.USB_FUNCTION_MTP; } else if (preference == mPtp && mPtp.isChecked()) { function = UsbManager.USB_FUNCTION_PTP; + } else if (preference == mMidi && mMidi.isChecked()) { + function = UsbManager.USB_FUNCTION_MIDI; } mUsbManager.setCurrentFunction(function, true); diff --git a/src/com/android/settings/drawable/CircleFramedDrawable.java b/src/com/android/settings/drawable/CircleFramedDrawable.java index 97c96a0..31b8922 100644 --- a/src/com/android/settings/drawable/CircleFramedDrawable.java +++ b/src/com/android/settings/drawable/CircleFramedDrawable.java @@ -42,45 +42,22 @@ public class CircleFramedDrawable extends Drawable { private final Bitmap mBitmap; private final int mSize; private final Paint mPaint; - private final float mShadowRadius; - private final float mStrokeWidth; - private final int mFrameColor; - private final int mHighlightColor; - private final int mFrameShadowColor; private float mScale; - private Path mFramePath; private Rect mSrcRect; private RectF mDstRect; - private RectF mFrameRect; - private boolean mPressed; public static CircleFramedDrawable getInstance(Context context, Bitmap icon) { Resources res = context.getResources(); float iconSize = res.getDimension(R.dimen.circle_avatar_size); - float strokeWidth = res.getDimension(R.dimen.circle_avatar_frame_stroke_width); - float shadowRadius = res.getDimension(R.dimen.circle_avatar_frame_shadow_radius); - int frameColor = res.getColor(R.color.circle_avatar_frame_color); - int frameShadowColor = res.getColor(R.color.circle_avatar_frame_shadow_color); - int highlightColor = res.getColor(R.color.circle_avatar_frame_pressed_color); - - CircleFramedDrawable instance = new CircleFramedDrawable(icon, - (int) iconSize, frameColor, strokeWidth, frameShadowColor, shadowRadius, - highlightColor); + + CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize); return instance; } - public CircleFramedDrawable(Bitmap icon, int size, - int frameColor, float strokeWidth, - int frameShadowColor, float shadowRadius, - int highlightColor) { + public CircleFramedDrawable(Bitmap icon, int size) { super(); mSize = size; - mShadowRadius = shadowRadius; - mFrameColor = frameColor; - mFrameShadowColor = frameShadowColor; - mStrokeWidth = strokeWidth; - mHighlightColor = highlightColor; mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(mBitmap); @@ -91,8 +68,6 @@ public class CircleFramedDrawable extends Drawable { final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square); final RectF circleRect = new RectF(0f, 0f, mSize, mSize); - circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); - circleRect.inset(mShadowRadius, mShadowRadius); final Path fillPath = new Path(); fillPath.addArc(circleRect, 0f, 360f); @@ -117,8 +92,6 @@ public class CircleFramedDrawable extends Drawable { mSrcRect = new Rect(0, 0, mSize, mSize); mDstRect = new RectF(0, 0, mSize, mSize); - mFrameRect = new RectF(mDstRect); - mFramePath = new Path(); } @Override @@ -128,28 +101,6 @@ public class CircleFramedDrawable extends Drawable { mDstRect.set(pad, pad, mSize - pad, mSize - pad); canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null); - - mFrameRect.set(mDstRect); - mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); - mFrameRect.inset(mShadowRadius, mShadowRadius); - - mFramePath.reset(); - mFramePath.addArc(mFrameRect, 0f, 360f); - - // white frame - if (mPressed) { - mPaint.setStyle(Paint.Style.FILL); - mPaint.setColor(Color.argb((int) (0.33f * 255), - Color.red(mHighlightColor), - Color.green(mHighlightColor), - Color.blue(mHighlightColor))); - canvas.drawPath(mFramePath, mPaint); - } - mPaint.setStrokeWidth(mStrokeWidth); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setColor(mPressed ? mHighlightColor : mFrameColor); - mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor); - canvas.drawPath(mFramePath, mPaint); } public void setScale(float scale) { @@ -160,10 +111,6 @@ public class CircleFramedDrawable extends Drawable { return mScale; } - public void setPressed(boolean pressed) { - mPressed = pressed; - } - @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; diff --git a/src/com/android/settings/notification/NotificationAppList.java b/src/com/android/settings/notification/NotificationAppList.java index cd1474f..311ec59 100644 --- a/src/com/android/settings/notification/NotificationAppList.java +++ b/src/com/android/settings/notification/NotificationAppList.java @@ -18,6 +18,7 @@ package com.android.settings.notification; import static com.android.settings.notification.AppNotificationSettings.EXTRA_HAS_SETTINGS_INTENT; import static com.android.settings.notification.AppNotificationSettings.EXTRA_SETTINGS_INTENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.animation.LayoutTransition; import android.app.INotificationManager; @@ -49,6 +50,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; @@ -127,6 +129,8 @@ public class NotificationAppList extends PinnedHeaderListFragment R.layout.spinner_view, null); mSpinner.setAdapter(mProfileSpinnerAdapter); mSpinner.setOnItemSelectedListener(this); + // Set layout parameters, otherwise we get the default ones + mSpinner.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); setPinnedHeaderView(mSpinner); } } diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java index 420f974..556296c 100644 --- a/src/com/android/settings/notification/ZenModeSettings.java +++ b/src/com/android/settings/notification/ZenModeSettings.java @@ -197,8 +197,8 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index mStarred = (DropDownPreference) important.findPreference(KEY_STARRED); mStarred.addItem(R.string.zen_mode_from_anyone, ZenModeConfig.SOURCE_ANYONE); - mStarred.addItem(R.string.zen_mode_from_starred, ZenModeConfig.SOURCE_STAR); mStarred.addItem(R.string.zen_mode_from_contacts, ZenModeConfig.SOURCE_CONTACT); + mStarred.addItem(R.string.zen_mode_from_starred, ZenModeConfig.SOURCE_STAR); mStarred.setCallback(new DropDownPreference.Callback() { @Override public boolean onItemSelected(int pos, Object newValue) { diff --git a/src/com/android/settings/print/PrintSettingsUtils.java b/src/com/android/settings/print/PrintSettingsUtils.java index 24f20d5..ad866a0 100644 --- a/src/com/android/settings/print/PrintSettingsUtils.java +++ b/src/com/android/settings/print/PrintSettingsUtils.java @@ -19,6 +19,7 @@ package com.android.settings.print; import android.content.ComponentName; import android.content.Context; import android.provider.Settings; +import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import java.util.ArrayList;import java.util.List; @@ -39,7 +40,7 @@ public class PrintSettingsUtils { String enabledServicesSetting = Settings.Secure.getString(context .getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES); - if (enabledServicesSetting == null) { + if (TextUtils.isEmpty(enabledServicesSetting)) { return enabledServices; } @@ -51,7 +52,9 @@ public class PrintSettingsUtils { String componentNameString = colonSplitter.next(); ComponentName enabledService = ComponentName.unflattenFromString( componentNameString); - enabledServices.add(enabledService); + if (enabledService != null) { + enabledServices.add(enabledService); + } } return enabledServices; diff --git a/src/com/android/settings/quicklaunch/BookmarkPicker.java b/src/com/android/settings/quicklaunch/BookmarkPicker.java deleted file mode 100644 index 32594b6..0000000 --- a/src/com/android/settings/quicklaunch/BookmarkPicker.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.settings.quicklaunch; - -import com.android.settings.R; - -import android.app.ListActivity; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.SimpleAdapter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * Activity to pick a bookmark that will be returned to the caller. - * <p> - * Currently, bookmarks are either: - * <li> Activities that are in the launcher - * <li> Activities that are within an app that is capable of being launched with - * the {@link Intent#ACTION_CREATE_SHORTCUT}. - */ -public class BookmarkPicker extends ListActivity implements SimpleAdapter.ViewBinder { - - private static final String TAG = "BookmarkPicker"; - - /** Extra in the returned intent from this activity. */ - public static final String EXTRA_TITLE = "com.android.settings.quicklaunch.TITLE"; - - /** Extra that should be provided, and will be returned. */ - public static final String EXTRA_SHORTCUT = "com.android.settings.quicklaunch.SHORTCUT"; - - /** - * The request code for the screen to create a bookmark that is WITHIN an - * application. For example, Gmail can return a bookmark for the inbox - * folder. - */ - private static final int REQUEST_CREATE_SHORTCUT = 1; - - /** Intent used to get all the activities that are launch-able */ - private static Intent sLaunchIntent; - /** Intent used to get all the activities that are {@link #REQUEST_CREATE_SHORTCUT}-able */ - private static Intent sShortcutIntent; - - /** - * List of ResolveInfo for activities that we can bookmark (either directly - * to the activity, or by launching the activity and it returning a bookmark - * WITHIN that application). - */ - private List<ResolveInfo> mResolveList; - - // List adapter stuff - private static final String KEY_TITLE = "TITLE"; - private static final String KEY_RESOLVE_INFO = "RESOLVE_INFO"; - private static final String sKeys[] = new String[] { KEY_TITLE, KEY_RESOLVE_INFO }; - private static final int sResourceIds[] = new int[] { R.id.title, R.id.icon }; - private SimpleAdapter mMyAdapter; - - /** Display those activities that are launch-able */ - private static final int DISPLAY_MODE_LAUNCH = 0; - /** Display those activities that are able to have bookmarks WITHIN the application */ - private static final int DISPLAY_MODE_SHORTCUT = 1; - private int mDisplayMode = DISPLAY_MODE_LAUNCH; - - private Handler mUiHandler = new Handler(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - updateListAndAdapter(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, DISPLAY_MODE_LAUNCH, 0, R.string.quick_launch_display_mode_applications) - .setIcon(com.android.internal.R.drawable.ic_menu_archive); - menu.add(0, DISPLAY_MODE_SHORTCUT, 0, R.string.quick_launch_display_mode_shortcuts) - .setIcon(com.android.internal.R.drawable.ic_menu_goto); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.findItem(DISPLAY_MODE_LAUNCH).setVisible(mDisplayMode != DISPLAY_MODE_LAUNCH); - menu.findItem(DISPLAY_MODE_SHORTCUT).setVisible(mDisplayMode != DISPLAY_MODE_SHORTCUT); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - switch (item.getItemId()) { - - case DISPLAY_MODE_LAUNCH: - mDisplayMode = DISPLAY_MODE_LAUNCH; - break; - - case DISPLAY_MODE_SHORTCUT: - mDisplayMode = DISPLAY_MODE_SHORTCUT; - break; - - default: - return false; - } - - updateListAndAdapter(); - return true; - } - - private void ensureIntents() { - if (sLaunchIntent == null) { - sLaunchIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER); - sShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); - } - } - - /** - * This should be called from the UI thread. - */ - private void updateListAndAdapter() { - // Get the activities in a separate thread - new Thread("data updater") { - @Override - public void run() { - synchronized (BookmarkPicker.this) { - /* - * Don't touch any of the lists that are being used by the - * adapter in this thread! - */ - ArrayList<ResolveInfo> newResolveList = new ArrayList<ResolveInfo>(); - ArrayList<Map<String, ?>> newAdapterList = new ArrayList<Map<String, ?>>(); - - fillResolveList(newResolveList); - Collections.sort(newResolveList, - new ResolveInfo.DisplayNameComparator(getPackageManager())); - - fillAdapterList(newAdapterList, newResolveList); - - updateAdapterToUseNewLists(newAdapterList, newResolveList); - } - } - }.start(); - } - - private void updateAdapterToUseNewLists(final ArrayList<Map<String, ?>> newAdapterList, - final ArrayList<ResolveInfo> newResolveList) { - // Post this back on the UI thread - mUiHandler.post(new Runnable() { - public void run() { - /* - * SimpleAdapter does not support changing the lists after it - * has been created. We just create a new instance. - */ - mMyAdapter = createResolveAdapter(newAdapterList); - mResolveList = newResolveList; - setListAdapter(mMyAdapter); - } - }); - } - - /** - * Gets all activities matching our current display mode. - * - * @param list The list to fill. - */ - private void fillResolveList(List<ResolveInfo> list) { - ensureIntents(); - PackageManager pm = getPackageManager(); - list.clear(); - - if (mDisplayMode == DISPLAY_MODE_LAUNCH) { - list.addAll(pm.queryIntentActivities(sLaunchIntent, 0)); - } else if (mDisplayMode == DISPLAY_MODE_SHORTCUT) { - list.addAll(pm.queryIntentActivities(sShortcutIntent, 0)); - } - } - - private SimpleAdapter createResolveAdapter(List<Map<String, ?>> list) { - SimpleAdapter adapter = new SimpleAdapter(this, list, - R.layout.bookmark_picker_item, sKeys, sResourceIds); - adapter.setViewBinder(this); - return adapter; - } - - private void fillAdapterList(List<Map<String, ?>> list, - List<ResolveInfo> resolveList) { - list.clear(); - int resolveListSize = resolveList.size(); - for (int i = 0; i < resolveListSize; i++) { - ResolveInfo info = resolveList.get(i); - /* - * Simple adapter craziness. For each item, we need to create a map - * from a key to its value (the value can be any object--the view - * binder will take care of filling the View with a representation - * of that object). - */ - Map<String, Object> map = new TreeMap<String, Object>(); - map.put(KEY_TITLE, getResolveInfoTitle(info)); - map.put(KEY_RESOLVE_INFO, info); - list.add(map); - } - } - - /** Get the title for a resolve info. */ - private String getResolveInfoTitle(ResolveInfo info) { - CharSequence label = info.loadLabel(getPackageManager()); - if (label == null) label = info.activityInfo.name; - return label != null ? label.toString() : null; - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - if (position >= mResolveList.size()) return; - - ResolveInfo info = mResolveList.get(position); - - switch (mDisplayMode) { - - case DISPLAY_MODE_LAUNCH: - // We can go ahead and return the clicked info's intent - Intent intent = getIntentForResolveInfo(info, Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - finish(intent, getResolveInfoTitle(info)); - break; - - case DISPLAY_MODE_SHORTCUT: - // Start the shortcut activity so the user can pick the actual intent - // (example: Gmail's shortcut activity shows a list of mailboxes) - startShortcutActivity(info); - break; - } - - } - - private static Intent getIntentForResolveInfo(ResolveInfo info, String action) { - Intent intent = new Intent(action); - ActivityInfo ai = info.activityInfo; - intent.setClassName(ai.packageName, ai.name); - return intent; - } - - /** - * Starts an activity to get a shortcut. - * <p> - * For example, Gmail has an activity that lists the available labels. It - * returns a shortcut intent for going directly to this label. - */ - private void startShortcutActivity(ResolveInfo info) { - Intent intent = getIntentForResolveInfo(info, Intent.ACTION_CREATE_SHORTCUT); - startActivityForResult(intent, REQUEST_CREATE_SHORTCUT); - - // Will get a callback to onActivityResult - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode != RESULT_OK) { - return; - } - - switch (requestCode) { - - case REQUEST_CREATE_SHORTCUT: - if (data != null) { - finish((Intent) data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT), - data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME)); - } - break; - - default: - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - - /** - * Finishes the activity and returns the given data. - */ - private void finish(Intent intent, String title) { - // Give back what was given to us (it will have the shortcut, for example) - intent.putExtras(getIntent()); - // Put our information - intent.putExtra(EXTRA_TITLE, title); - setResult(RESULT_OK, intent); - finish(); - } - - /** - * {@inheritDoc} - */ - public boolean setViewValue(View view, Object data, String textRepresentation) { - if (view.getId() == R.id.icon) { - Drawable icon = ((ResolveInfo) data).loadIcon(getPackageManager()); - if (icon != null) { - ((ImageView) view).setImageDrawable(icon); - } - return true; - } else { - return false; - } - } - -} diff --git a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java deleted file mode 100644 index 1367018..0000000 --- a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * 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 com.android.settings.quicklaunch; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.ContentObserver; -import android.database.Cursor; -import android.os.Bundle; -import android.os.Handler; -import android.preference.Preference; -import android.preference.PreferenceGroup; -import android.preference.PreferenceScreen; -import android.provider.Settings.Bookmarks; -import android.util.Log; -import android.util.SparseArray; -import android.util.SparseBooleanArray; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.View; -import android.widget.AdapterView; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import java.net.URISyntaxException; - -/** - * Settings activity for quick launch. - * <p> - * Shows a list of possible shortcuts, the current application each is bound to, - * and allows choosing a new bookmark for a shortcut. - */ -public class QuickLaunchSettings extends SettingsPreferenceFragment implements - AdapterView.OnItemLongClickListener, DialogInterface.OnClickListener { - - private static final String TAG = "QuickLaunchSettings"; - - private static final String KEY_SHORTCUT_CATEGORY = "shortcut_category"; - - private static final int DIALOG_CLEAR_SHORTCUT = 0; - - private static final int REQUEST_PICK_BOOKMARK = 1; - - private static final int COLUMN_SHORTCUT = 0; - private static final int COLUMN_TITLE = 1; - private static final int COLUMN_INTENT = 2; - private static final String[] sProjection = new String[] { - Bookmarks.SHORTCUT, Bookmarks.TITLE, Bookmarks.INTENT - }; - private static final String sShortcutSelection = Bookmarks.SHORTCUT + "=?"; - - private Handler mUiHandler = new Handler(); - - private static final String DEFAULT_BOOKMARK_FOLDER = "@quicklaunch"; - /** Cursor for Bookmarks provider. */ - private Cursor mBookmarksCursor; - /** Listens for changes to Bookmarks provider. */ - private BookmarksObserver mBookmarksObserver; - /** Used to keep track of which shortcuts have bookmarks. */ - private SparseBooleanArray mBookmarkedShortcuts; - - /** Preference category to hold the shortcut preferences. */ - private PreferenceGroup mShortcutGroup; - /** Mapping of a shortcut to its preference. */ - private SparseArray<ShortcutPreference> mShortcutToPreference; - - /** The bookmark title of the shortcut that is being cleared. */ - private CharSequence mClearDialogBookmarkTitle; - private static final String CLEAR_DIALOG_BOOKMARK_TITLE = "CLEAR_DIALOG_BOOKMARK_TITLE"; - /** The shortcut that is being cleared. */ - private char mClearDialogShortcut; - private static final String CLEAR_DIALOG_SHORTCUT = "CLEAR_DIALOG_SHORTCUT"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.quick_launch_settings); - - mShortcutGroup = (PreferenceGroup) findPreference(KEY_SHORTCUT_CATEGORY); - mShortcutToPreference = new SparseArray<ShortcutPreference>(); - mBookmarksObserver = new BookmarksObserver(mUiHandler); - initShortcutPreferences(); - mBookmarksCursor = getActivity().getContentResolver().query(Bookmarks.CONTENT_URI, - sProjection, null, null, null); - } - - @Override - public void onResume() { - super.onResume(); - mBookmarksCursor = getActivity().getContentResolver().query(Bookmarks.CONTENT_URI, - sProjection, null, null, null); - getContentResolver().registerContentObserver(Bookmarks.CONTENT_URI, true, - mBookmarksObserver); - refreshShortcuts(); - } - - @Override - public void onPause() { - super.onPause(); - getContentResolver().unregisterContentObserver(mBookmarksObserver); - } - - @Override - public void onStop() { - super.onStop(); - mBookmarksCursor.close(); - } - - @Override - public void onActivityCreated(Bundle state) { - super.onActivityCreated(state); - - getListView().setOnItemLongClickListener(this); - - if (state != null) { - // Restore the clear dialog's info - mClearDialogBookmarkTitle = state.getString(CLEAR_DIALOG_BOOKMARK_TITLE); - mClearDialogShortcut = (char) state.getInt(CLEAR_DIALOG_SHORTCUT, 0); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - // Save the clear dialog's info - outState.putCharSequence(CLEAR_DIALOG_BOOKMARK_TITLE, mClearDialogBookmarkTitle); - outState.putInt(CLEAR_DIALOG_SHORTCUT, mClearDialogShortcut); - } - - @Override - public Dialog onCreateDialog(int id) { - switch (id) { - - case DIALOG_CLEAR_SHORTCUT: { - // Create the dialog for clearing a shortcut - return new AlertDialog.Builder(getActivity()) - .setTitle(getString(R.string.quick_launch_clear_dialog_title)) - .setMessage(getString(R.string.quick_launch_clear_dialog_message, - mClearDialogShortcut, mClearDialogBookmarkTitle)) - .setPositiveButton(R.string.quick_launch_clear_ok_button, this) - .setNegativeButton(R.string.quick_launch_clear_cancel_button, this) - .create(); - } - } - - return super.onCreateDialog(id); - } - - private void showClearDialog(ShortcutPreference pref) { - - if (!pref.hasBookmark()) return; - - mClearDialogBookmarkTitle = pref.getTitle(); - mClearDialogShortcut = pref.getShortcut(); - showDialog(DIALOG_CLEAR_SHORTCUT); - } - - public void onClick(DialogInterface dialog, int which) { - if (mClearDialogShortcut > 0 && which == AlertDialog.BUTTON_POSITIVE) { - // Clear the shortcut - clearShortcut(mClearDialogShortcut); - } - mClearDialogBookmarkTitle = null; - mClearDialogShortcut = 0; - } - - private void clearShortcut(char shortcut) { - getContentResolver().delete(Bookmarks.CONTENT_URI, sShortcutSelection, - new String[] { String.valueOf((int) shortcut) }); - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { - if (!(preference instanceof ShortcutPreference)) return false; - - // Open the screen to pick a bookmark for this shortcut - ShortcutPreference pref = (ShortcutPreference) preference; - Intent intent = new Intent(getActivity(), BookmarkPicker.class); - intent.putExtra(BookmarkPicker.EXTRA_SHORTCUT, pref.getShortcut()); - startActivityForResult(intent, REQUEST_PICK_BOOKMARK); - - return true; - } - - public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { - - // Open the clear shortcut dialog - Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(position); - if (!(pref instanceof ShortcutPreference)) return false; - showClearDialog((ShortcutPreference) pref); - return true; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode != Activity.RESULT_OK) { - return; - } - - if (requestCode == REQUEST_PICK_BOOKMARK) { - - // Returned from the 'pick bookmark for this shortcut' screen - if (data == null) { - Log.w(TAG, "Result from bookmark picker does not have an intent."); - return; - } - - char shortcut = data.getCharExtra(BookmarkPicker.EXTRA_SHORTCUT, (char) 0); - updateShortcut(shortcut, data); - - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - private void updateShortcut(char shortcut, Intent intent) { - // Update the bookmark for a shortcut - // Pass an empty title so it gets resolved each time this bookmark is - // displayed (since the locale could change after we insert into the provider). - Bookmarks.add(getContentResolver(), intent, "", DEFAULT_BOOKMARK_FOLDER, shortcut, 0); - } - - private ShortcutPreference getOrCreatePreference(char shortcut) { - ShortcutPreference pref = mShortcutToPreference.get(shortcut); - if (pref != null) { - return pref; - } else { - Log.w(TAG, "Unknown shortcut '" + shortcut + "', creating preference anyway"); - return createPreference(shortcut); - } - } - - private ShortcutPreference createPreference(char shortcut) { - ShortcutPreference pref = new ShortcutPreference(getActivity(), shortcut); - mShortcutGroup.addPreference(pref); - mShortcutToPreference.put(shortcut, pref); - return pref; - } - - private void initShortcutPreferences() { - - /** Whether the shortcut has been seen already. The array index is the shortcut. */ - SparseBooleanArray shortcutSeen = new SparseBooleanArray(); - KeyCharacterMap keyMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - - // Go through all the key codes and create a preference for the appropriate keys - for (int keyCode = KeyEvent.getMaxKeyCode() - 1; keyCode >= 0; keyCode--) { - // Get the label for the primary char on the key that produces this key code - char shortcut = (char) Character.toLowerCase(keyMap.getDisplayLabel(keyCode)); - if (shortcut == 0 || shortcutSeen.get(shortcut, false)) continue; - // TODO: need a to tell if the current keyboard can produce this key code, for now - // only allow the letter or digits - if (!Character.isLetterOrDigit(shortcut)) continue; - shortcutSeen.put(shortcut, true); - - createPreference(shortcut); - } - } - - private synchronized void refreshShortcuts() { - Cursor c = mBookmarksCursor; - if (c == null) { - // Haven't finished querying yet - return; - } - - if (!c.requery()) { - Log.e(TAG, "Could not requery cursor when refreshing shortcuts."); - return; - } - - /** - * We use the previous bookmarked shortcuts array to filter out those - * shortcuts that had bookmarks before this method call, and don't after - * (so we can set the preferences to be without bookmarks). - */ - SparseBooleanArray noLongerBookmarkedShortcuts = mBookmarkedShortcuts; - SparseBooleanArray newBookmarkedShortcuts = new SparseBooleanArray(); - while (c.moveToNext()) { - char shortcut = Character.toLowerCase((char) c.getInt(COLUMN_SHORTCUT)); - if (shortcut == 0) continue; - - ShortcutPreference pref = getOrCreatePreference(shortcut); - CharSequence title = Bookmarks.getTitle(getActivity(), c); - - /* - * The title retrieved from Bookmarks.getTitle() will be in - * the original boot locale, not the current locale. - * Try to look up a localized title from the PackageManager. - */ - int intentColumn = c.getColumnIndex(Bookmarks.INTENT); - String intentUri = c.getString(intentColumn); - PackageManager packageManager = getPackageManager(); - try { - Intent intent = Intent.parseUri(intentUri, 0); - ResolveInfo info = packageManager.resolveActivity(intent, 0); - if (info != null) { - title = info.loadLabel(packageManager); - } - } catch (URISyntaxException e) { - // Just use the non-localized title, then. - } - - pref.setTitle(title); - pref.setSummary(getString(R.string.quick_launch_shortcut, - String.valueOf(shortcut))); - pref.setHasBookmark(true); - - newBookmarkedShortcuts.put(shortcut, true); - if (noLongerBookmarkedShortcuts != null) { - // After this loop, the shortcuts with value true in this array - // will no longer have bookmarks - noLongerBookmarkedShortcuts.put(shortcut, false); - } - } - - if (noLongerBookmarkedShortcuts != null) { - for (int i = noLongerBookmarkedShortcuts.size() - 1; i >= 0; i--) { - if (noLongerBookmarkedShortcuts.valueAt(i)) { - // True, so there is no longer a bookmark for this shortcut - char shortcut = (char) noLongerBookmarkedShortcuts.keyAt(i); - ShortcutPreference pref = mShortcutToPreference.get(shortcut); - if (pref != null) { - pref.setHasBookmark(false); - } - } - } - } - - mBookmarkedShortcuts = newBookmarkedShortcuts; - - c.deactivate(); - } - - private class BookmarksObserver extends ContentObserver { - - public BookmarksObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - - refreshShortcuts(); - } - } -} diff --git a/src/com/android/settings/quicklaunch/ShortcutPreference.java b/src/com/android/settings/quicklaunch/ShortcutPreference.java deleted file mode 100644 index 92efdeb..0000000 --- a/src/com/android/settings/quicklaunch/ShortcutPreference.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.settings.quicklaunch; - -import com.android.settings.R; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.preference.Preference; -import android.util.TypedValue; -import android.view.View; -import android.widget.TextView; - -/** - * Preference type for a shortcut in {@link QuickLaunchSettings}. - */ -public class ShortcutPreference extends Preference implements Comparable<Preference> { - - private static Object sStaticVarsLock = new Object(); - - // These static fields are used across all instances of ShortcutPreference. - // There will be many ShortcutPreference instances (~36 for US). - private static String STRING_ASSIGN_APPLICATION; - private static String STRING_NO_SHORTCUT; - - private static int sDimAlpha; - private static ColorStateList sRegularTitleColor; - private static ColorStateList sDimTitleColor; - private static ColorStateList sRegularSummaryColor; - private static ColorStateList sDimSummaryColor; - - private char mShortcut; - private boolean mHasBookmark; - - public ShortcutPreference(Context context, char shortcut) { - super(context); - - synchronized (sStaticVarsLock) { - // Init statics. This should only happen for the first ShortcutPreference created, - // the rest will already have them initialized. - if (STRING_ASSIGN_APPLICATION == null) { - STRING_ASSIGN_APPLICATION = context.getString(R.string.quick_launch_assign_application); - STRING_NO_SHORTCUT = context.getString(R.string.quick_launch_no_shortcut); - - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); - sDimAlpha = (int) (outValue.getFloat() * 255); - } - } - - mShortcut = shortcut; - - setWidgetLayoutResource(R.layout.preference_widget_shortcut); - } - - public char getShortcut() { - return mShortcut; - } - - public void setShortcut(char shortcut) { - if (shortcut != mShortcut) { - mShortcut = shortcut; - notifyChanged(); - } - } - - public boolean hasBookmark() { - return mHasBookmark; - } - - public void setHasBookmark(boolean hasBookmark) { - if (hasBookmark != mHasBookmark) { - mHasBookmark = hasBookmark; - notifyChanged(); - } - } - - @Override - public CharSequence getTitle() { - return mHasBookmark ? super.getTitle() : STRING_ASSIGN_APPLICATION; - } - - @Override - public CharSequence getSummary() { - return mHasBookmark ? super.getSummary() : STRING_NO_SHORTCUT; - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - - TextView shortcutView = (TextView) view.findViewById(R.id.shortcut); - if (shortcutView != null) { - shortcutView.setText(String.valueOf(mShortcut)); - } - - TextView titleView = (TextView) view.findViewById(android.R.id.title); - - synchronized (sStaticVarsLock) { - if (sRegularTitleColor == null) { - sRegularTitleColor = titleView.getTextColors(); - sDimTitleColor = sRegularTitleColor.withAlpha(sDimAlpha); - } - } - - ColorStateList color = mHasBookmark ? sRegularTitleColor : sDimTitleColor; - if (color != null) { - titleView.setTextColor(color); - } - - TextView summaryView = (TextView) view.findViewById(android.R.id.summary); - - synchronized (sStaticVarsLock) { - if (sRegularSummaryColor == null) { - sRegularSummaryColor = summaryView.getTextColors(); - sDimSummaryColor = sRegularSummaryColor.withAlpha(sDimAlpha); - } - } - - color = mHasBookmark ? sRegularSummaryColor : sDimSummaryColor; - if (color != null) { - summaryView.setTextColor(color); - } - - } - - public int compareTo(Preference another) { - if (!(another instanceof ShortcutPreference)) return super.compareTo(another); - - // Letters before digits - char other = ((ShortcutPreference) another).mShortcut; - if (Character.isDigit(mShortcut) && Character.isLetter(other)) return 1; - else if (Character.isDigit(other) && Character.isLetter(mShortcut)) return -1; - else return mShortcut - other; - } - -} diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java index 3170dae..e9234d7 100644 --- a/src/com/android/settings/sim/SimDialogActivity.java +++ b/src/com/android/settings/sim/SimDialogActivity.java @@ -29,6 +29,7 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -138,17 +139,14 @@ public class SimDialogActivity extends Activity { private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) { final TelecomManager telecomManager = TelecomManager.from(this); + final TelephonyManager telephonyManager = TelephonyManager.from(this); final Iterator<PhoneAccountHandle> phoneAccounts = telecomManager.getCallCapablePhoneAccounts().listIterator(); while (phoneAccounts.hasNext()) { final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next(); final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle); - final String phoneAccountId = phoneAccountHandle.getId(); - - if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) - && TextUtils.isDigitsOnly(phoneAccountId) - && Integer.parseInt(phoneAccountId) == subId){ + if (subId == telephonyManager.getSubIdForPhoneAccount(phoneAccount)) { return phoneAccountHandle; } } @@ -210,6 +208,7 @@ public class SimDialogActivity extends Activity { ArrayList<SubscriptionInfo> callsSubInfoList = new ArrayList<SubscriptionInfo>(); if (id == CALLS_PICK) { final TelecomManager telecomManager = TelecomManager.from(context); + final TelephonyManager telephonyManager = TelephonyManager.from(context); final Iterator<PhoneAccountHandle> phoneAccounts = telecomManager.getCallCapablePhoneAccounts().listIterator(); @@ -219,13 +218,9 @@ public class SimDialogActivity extends Activity { final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccounts.next()); list.add((String)phoneAccount.getLabel()); - // Added check to add entry into callsSubInforList only if phoneAccountId is int - // Todo : Might have to change it later based on b/18904714 - if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && - TextUtils.isDigitsOnly(phoneAccount.getAccountHandle().getId())) { - final String phoneAccountId = phoneAccount.getAccountHandle().getId(); - final SubscriptionInfo sir = Utils.findRecordBySubId(context, - Integer.parseInt(phoneAccountId)); + int subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount); + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + final SubscriptionInfo sir = Utils.findRecordBySubId(context, subId); callsSubInfoList.add(sir); } else { callsSubInfoList.add(null); diff --git a/src/com/android/settings/sim/SimSettings.java b/src/com/android/settings/sim/SimSettings.java index 5d963ed..3ebc250 100644 --- a/src/com/android/settings/sim/SimSettings.java +++ b/src/com/android/settings/sim/SimSettings.java @@ -230,11 +230,14 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable final TelecomManager telecomManager = TelecomManager.from(getActivity()); final PhoneAccountHandle phoneAccount = telecomManager.getUserSelectedOutgoingPhoneAccount(); + final List<PhoneAccountHandle> allPhoneAccounts = + telecomManager.getCallCapablePhoneAccounts(); simPref.setTitle(R.string.calls_title); simPref.setSummary(phoneAccount == null ? getResources().getString(R.string.sim_calls_ask_first_prefs_title) : (String)telecomManager.getPhoneAccount(phoneAccount).getLabel()); + simPref.setEnabled(allPhoneAccounts.size() > 1); } @Override diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java index c28f1ff..37b1813 100644 --- a/src/com/android/settings/users/AppRestrictionsFragment.java +++ b/src/com/android/settings/users/AppRestrictionsFragment.java @@ -50,9 +50,9 @@ import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; -import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.Switch; @@ -180,16 +180,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen return immutable; } - RestrictionEntry getRestriction(String key) { - if (restrictions == null) return null; - for (RestrictionEntry entry : restrictions) { - if (entry.getKey().equals(key)) { - return entry; - } - } - return null; - } - ArrayList<RestrictionEntry> getRestrictions() { return restrictions; } @@ -327,16 +317,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen return getPreferenceScreen(); } - Drawable getCircularUserIcon() { - Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier()); - if (userIcon == null) { - return null; - } - CircleFramedDrawable circularIcon = - CircleFramedDrawable.getInstance(this.getActivity(), userIcon); - return circularIcon; - } - protected void clearSelectedApps() { mSelectedPackages.clear(); } @@ -655,25 +635,16 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen mAppList.removeAll(); Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES); final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0); - int i = 0; for (SelectableAppInfo app : mVisibleApps) { String packageName = app.packageName; if (packageName == null) continue; final boolean isSettingsApp = packageName.equals(context.getPackageName()); AppRestrictionsPreference p = new AppRestrictionsPreference(context, this); final boolean hasSettings = resolveInfoListHasPackage(receivers, packageName); - p.setIcon(app.icon != null ? app.icon.mutate() : null); - p.setChecked(false); - p.setTitle(app.activityName); - if (app.masterEntry != null) { - p.setSummary(context.getString(R.string.user_restrictions_controlled_by, - app.masterEntry.activityName)); + if (isSettingsApp) { + addLocationAppRestrictionsPreference(app, p); + continue; } - p.setKey(getKeyForPackage(packageName)); - p.setSettingsEnabled((hasSettings || isSettingsApp) && app.masterEntry == null); - p.setPersistent(false); - p.setOnPreferenceChangeListener(this); - p.setOnPreferenceClickListener(this); PackageInfo pi = null; try { pi = ipm.getPackageInfo(packageName, @@ -684,44 +655,41 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen if (pi == null) { continue; } + if (mRestrictedProfile && isAppUnsupportedInRestrictedProfile(pi)) { + continue; + } + p.setIcon(app.icon != null ? app.icon.mutate() : null); + p.setChecked(false); + p.setTitle(app.activityName); + p.setKey(getKeyForPackage(packageName)); + p.setSettingsEnabled(hasSettings && app.masterEntry == null); + p.setPersistent(false); + p.setOnPreferenceChangeListener(this); + p.setOnPreferenceClickListener(this); + p.setSummary(getPackageSummary(pi, app)); if (pi.requiredForAllUsers || isPlatformSigned(pi)) { p.setChecked(true); p.setImmutable(true); // If the app is required and has no restrictions, skip showing it - if (!hasSettings && !isSettingsApp) continue; + if (!hasSettings) continue; // Get and populate the defaults, since the user is not going to be // able to toggle this app ON (it's ON by default and immutable). // Only do this for restricted profiles, not single-user restrictions // Also don't do this for slave icons - if (hasSettings && app.masterEntry == null) { + if (app.masterEntry == null) { requestRestrictionsForApp(packageName, p, false); } } else if (!mNewUser && isAppEnabledForUser(pi)) { p.setChecked(true); } - if (mRestrictedProfile - && pi.requiredAccountType != null && pi.restrictedAccountType == null) { - p.setChecked(false); - p.setImmutable(true); - p.setSummary(R.string.app_not_supported_in_limited); - } - if (mRestrictedProfile && pi.restrictedAccountType != null) { - p.setSummary(R.string.app_sees_restricted_accounts); - } if (app.masterEntry != null) { p.setImmutable(true); p.setChecked(mSelectedPackages.get(packageName)); } - mAppList.addPreference(p); - if (isSettingsApp) { - p.setOrder(MAX_APP_RESTRICTIONS * 1); - } else { - p.setOrder(MAX_APP_RESTRICTIONS * (i + 2)); - } - mSelectedPackages.put(packageName, p.isChecked()); - mAppListChanged = true; - i++; + p.setOrder(MAX_APP_RESTRICTIONS * (mAppList.getPreferenceCount() + 2)); + addToAppList(p, packageName); } + mAppListChanged = true; // If this is the first time for a new profile, install/uninstall default apps for profile // to avoid taking the hit in onPause(), which can cause race conditions on user switch. if (mNewUser && mFirstTime) { @@ -730,6 +698,52 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen } } + private String getPackageSummary(PackageInfo pi, SelectableAppInfo app) { + // Check for 3 cases: + // - Slave entry that can see primary user accounts + // - Slave entry that cannot see primary user accounts + // - Master entry that can see primary user accounts + // Otherwise no summary is returned + if (app.masterEntry != null) { + if (mRestrictedProfile && pi.restrictedAccountType != null) { + return getString(R.string.app_sees_restricted_accounts_and_controlled_by, + app.masterEntry.activityName); + } + return getString(R.string.user_restrictions_controlled_by, + app.masterEntry.activityName); + } else if (pi.restrictedAccountType != null) { + return getString(R.string.app_sees_restricted_accounts); + } + return null; + } + + private static boolean isAppUnsupportedInRestrictedProfile(PackageInfo pi) { + return pi.requiredAccountType != null && pi.restrictedAccountType == null; + } + + private void addLocationAppRestrictionsPreference(SelectableAppInfo app, + AppRestrictionsPreference p) { + String packageName = app.packageName; + p.setIcon(R.drawable.ic_settings_location); + p.setKey(getKeyForPackage(packageName)); + ArrayList<RestrictionEntry> restrictions = RestrictionUtils.getRestrictions( + getActivity(), mUser); + RestrictionEntry locationRestriction = restrictions.get(0); + p.setTitle(locationRestriction.getTitle()); + p.setRestrictions(restrictions); + p.setSummary(locationRestriction.getDescription()); + p.setChecked(locationRestriction.getSelectedState()); + p.setPersistent(false); + p.setOnPreferenceClickListener(this); + p.setOrder(MAX_APP_RESTRICTIONS); + addToAppList(p, packageName); + } + + private void addToAppList(AppRestrictionsPreference p, String packageName) { + mSelectedPackages.put(packageName, p.isChecked()); + mAppList.addPreference(p); + } + private String getKeyForPackage(String packageName) { return PKG_PREFIX + packageName; } @@ -773,6 +787,12 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen } else if (!pref.isImmutable()) { pref.setChecked(!pref.isChecked()); final String packageName = pref.getKey().substring(PKG_PREFIX.length()); + // Settings/Location is handled as a top-level entry + if (packageName.equals(getActivity().getPackageName())) { + pref.restrictions.get(0).setSelectedState(pref.isChecked()); + RestrictionUtils.setRestrictions(getActivity(), pref.restrictions, mUser); + return; + } mSelectedPackages.put(packageName, pref.isChecked()); if (pref.isChecked() && pref.hasSettings && pref.restrictions == null) { @@ -823,13 +843,9 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen default: continue; } - if (packageName.equals(getActivity().getPackageName())) { - RestrictionUtils.setRestrictions(getActivity(), restrictions, mUser); - } else { - mUserManager.setApplicationRestrictions(packageName, - RestrictionUtils.restrictionsToBundle(restrictions), - mUser); - } + mUserManager.setApplicationRestrictions(packageName, + RestrictionUtils.restrictionsToBundle(restrictions), + mUser); break; } } @@ -851,14 +867,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen removeRestrictionsForApp(preference); } else { String packageName = preference.getKey().substring(PKG_PREFIX.length()); - if (packageName.equals(getActivity().getPackageName())) { - // Settings, fake it by using user restrictions - ArrayList<RestrictionEntry> restrictions = RestrictionUtils.getRestrictions( - getActivity(), mUser); - onRestrictionsReceived(preference, packageName, restrictions); - } else { - requestRestrictionsForApp(packageName, preference, true /*invoke if custom*/); - } + requestRestrictionsForApp(packageName, preference, true /*invoke if custom*/); } preference.setPanelOpen(!preference.isPanelOpen()); } @@ -980,9 +989,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen ((MultiSelectListPreference)p).setEntryValues(entry.getChoiceValues()); ((MultiSelectListPreference)p).setEntries(entry.getChoiceEntries()); HashSet<String> set = new HashSet<String>(); - for (String s : entry.getAllSelectedStrings()) { - set.add(s); - } + Collections.addAll(set, entry.getAllSelectedStrings()); ((MultiSelectListPreference)p).setValues(set); ((MultiSelectListPreference)p).setDialogTitle(entry.getTitle()); break; diff --git a/src/com/android/settings/users/EditUserInfoController.java b/src/com/android/settings/users/EditUserInfoController.java index 0f844a7..ab77101 100644 --- a/src/com/android/settings/users/EditUserInfoController.java +++ b/src/com/android/settings/users/EditUserInfoController.java @@ -37,6 +37,7 @@ import android.widget.EditText; import android.widget.ImageView; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.drawable.CircleFramedDrawable; /** @@ -98,16 +99,6 @@ public class EditUserInfoController { } } - Drawable getCircularUserIcon(Activity activity) { - Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier()); - if (userIcon == null) { - return null; - } - CircleFramedDrawable circularIcon = - CircleFramedDrawable.getInstance(activity, userIcon); - return circularIcon; - } - public Dialog createDialog(final Fragment fragment, final Drawable currentUserIcon, final CharSequence currentUserName, int titleResId, final OnContentChangedCallback callback, UserHandle user) { @@ -131,7 +122,7 @@ public class EditUserInfoController { } else { drawable = currentUserIcon; if (drawable == null) { - drawable = getCircularUserIcon(activity); + drawable = Utils.getUserIcon(activity, mUserManager, info); } } userPhotoView.setImageDrawable(drawable); diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java index c0e8cb7..03a55d4 100644 --- a/src/com/android/settings/users/RestrictedProfileSettings.java +++ b/src/com/android/settings/users/RestrictedProfileSettings.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.UserHandle; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -31,8 +30,6 @@ import android.widget.TextView; import com.android.settings.R; import com.android.settings.Utils; -import java.util.List; - public class RestrictedProfileSettings extends AppRestrictionsFragment implements EditUserInfoController.OnContentChangedCallback { @@ -93,7 +90,7 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment } else { ((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name); ((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable( - getCircularUserIcon()); + Utils.getUserIcon(getActivity(), mUserManager, info)); } } @@ -129,7 +126,7 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment this, mUser); } else if (dialogId == DIALOG_CONFIRM_REMOVE) { Dialog dlg = - Utils.createRemoveConfirmationDialog(getActivity(), mUser.getIdentifier(), + UserDialogs.createRemoveDialog(getActivity(), mUser.getIdentifier(), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { removeUser(); diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index 366b628..d738dd6 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -28,7 +28,6 @@ import android.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; import java.util.List; @@ -55,7 +54,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_REMOVE = 1; private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2; - private static final int DIALOG_CONFIRM_ENABLE_CALLING_SMS = 3; + private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3; private UserManager mUserManager; private SwitchPreference mPhonePref; @@ -117,10 +116,18 @@ public class UserDetailsSettings extends SettingsPreferenceFragment @Override public boolean onPreferenceChange(Preference preference, Object newValue) { + if (Boolean.TRUE.equals(newValue)) { + showDialog(mGuestUser? DIALOG_CONFIRM_ENABLE_CALLING : DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS); + return false; + } + enableCallsAndSms(false); + return true; + } + + void enableCallsAndSms(boolean enabled) { + mPhonePref.setChecked(enabled); if (mGuestUser) { - // TODO: Show confirmation dialog: b/15761405 - mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, - !((Boolean) newValue)); + mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, !enabled); // SMS is always disabled for guest mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true); mUserManager.setDefaultGuestRestrictions(mDefaultGuestRestrictions); @@ -135,14 +142,11 @@ public class UserDetailsSettings extends SettingsPreferenceFragment } } } else { - // TODO: Show confirmation dialog: b/15761405 UserHandle userHandle = new UserHandle(mUserInfo.id); - mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, - !((Boolean) newValue), userHandle); - mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, - !((Boolean) newValue), userHandle); + mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, + userHandle); + mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle); } - return true; } @Override @@ -150,20 +154,29 @@ public class UserDetailsSettings extends SettingsPreferenceFragment Context context = getActivity(); if (context == null) return null; switch (dialogId) { - case DIALOG_CONFIRM_REMOVE: { - Dialog dlg = Utils.createRemoveConfirmationDialog(getActivity(), mUserInfo.id, + case DIALOG_CONFIRM_REMOVE: + return UserDialogs.createRemoveDialog(getActivity(), mUserInfo.id, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { removeUser(); } }); - return dlg; - } case DIALOG_CONFIRM_ENABLE_CALLING: - case DIALOG_CONFIRM_ENABLE_CALLING_SMS: - // TODO: b/15761405 + return UserDialogs.createEnablePhoneCallsDialog(getActivity(), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + enableCallsAndSms(true); + } + }); + case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: + return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + enableCallsAndSms(true); + } + }); } - return null; + throw new IllegalArgumentException("Unsupported dialogId " + dialogId); } void removeUser() { diff --git a/src/com/android/settings/users/UserDialogs.java b/src/com/android/settings/users/UserDialogs.java new file mode 100644 index 0000000..2d92464 --- /dev/null +++ b/src/com/android/settings/users/UserDialogs.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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 com.android.settings.users; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; + +import com.android.settings.R; + +/** + * Helper class for displaying dialogs related to user settings. + */ +public final class UserDialogs { + + /** + * Creates a dialog to confirm with the user if it's ok to remove the user + * and delete all the data. + * + * @param context a Context object + * @param removingUserId The userId of the user to remove + * @param onConfirmListener Callback object for positive action + * @return the created Dialog + */ + public static Dialog createRemoveDialog(Context context, int removingUserId, + DialogInterface.OnClickListener onConfirmListener) { + UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); + UserInfo userInfo = um.getUserInfo(removingUserId); + int titleResId; + int messageResId; + if (UserHandle.myUserId() == removingUserId) { + titleResId = R.string.user_confirm_remove_self_title; + messageResId = R.string.user_confirm_remove_self_message; + } else if (userInfo.isRestricted()) { + titleResId = R.string.user_profile_confirm_remove_title; + messageResId = R.string.user_profile_confirm_remove_message; + } else if (userInfo.isManagedProfile()) { + titleResId = R.string.work_profile_confirm_remove_title; + messageResId = R.string.work_profile_confirm_remove_message; + } else { + titleResId = R.string.user_confirm_remove_title; + messageResId = R.string.user_confirm_remove_message; + } + return new AlertDialog.Builder(context) + .setTitle(titleResId) + .setMessage(messageResId) + .setPositiveButton(R.string.user_delete_button, onConfirmListener) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } + + /** + * Creates a dialog to confirm that the user is ok to enable phone calls and SMS. + * + * @param onConfirmListener Callback object for positive action + */ + public static Dialog createEnablePhoneCallsAndSmsDialog(Context context, + DialogInterface.OnClickListener onConfirmListener) { + return new AlertDialog.Builder(context) + .setTitle(R.string.user_enable_calling_and_sms_confirm_title) + .setMessage(R.string.user_enable_calling_and_sms_confirm_message) + .setPositiveButton(R.string.okay, onConfirmListener) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } + + /** + * Creates a dialog to confirm that the user is ok to enable phone calls (no SMS). + * + * @param onConfirmListener Callback object for positive action + */ + public static Dialog createEnablePhoneCallsDialog(Context context, + DialogInterface.OnClickListener onConfirmListener) { + return new AlertDialog.Builder(context) + .setTitle(R.string.user_enable_calling_confirm_title) + .setMessage(R.string.user_enable_calling_confirm_message) + .setPositiveButton(R.string.okay, onConfirmListener) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } +} diff --git a/src/com/android/settings/users/UserPreference.java b/src/com/android/settings/users/UserPreference.java index 23359ec..5079dd2 100644 --- a/src/com/android/settings/users/UserPreference.java +++ b/src/com/android/settings/users/UserPreference.java @@ -26,10 +26,26 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; +import java.util.Comparator; + public class UserPreference extends Preference { public static final int USERID_UNKNOWN = -10; public static final int USERID_GUEST_DEFAULTS = -11; + public static final Comparator<UserPreference> SERIAL_NUMBER_COMPARATOR = + new Comparator<UserPreference>() { + @Override + public int compare(UserPreference p1, UserPreference p2) { + int sn1 = p1.getSerialNumber(); + int sn2 = p2.getSerialNumber(); + if (sn1 < sn2) { + return -1; + } else if (sn1 > sn2) { + return 1; + } + return 0; + } + }; private OnClickListener mDeleteClickListener; private OnClickListener mSettingsClickListener; @@ -105,12 +121,4 @@ public class UserPreference extends Preference { public int getUserId() { return mUserId; } - - public int compareTo(Preference another) { - if (another instanceof UserPreference) { - return getSerialNumber() > ((UserPreference) another).getSerialNumber() ? 1 : -1; - } else { - return 1; - } - } } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index d7923ee..dbd0481 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -44,6 +44,7 @@ import android.os.UserManager; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; import android.provider.Settings; import android.provider.Settings.Secure; import android.util.Log; @@ -67,6 +68,7 @@ import com.android.settings.Utils; import com.android.settings.drawable.CircleFramedDrawable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -123,13 +125,14 @@ public class UserSettings extends SettingsPreferenceFragment private static final String KEY_SUMMARY = "summary"; private PreferenceGroup mUserListCategory; - private Preference mMePreference; + private UserPreference mMePreference; private SelectableEditTextPreference mNicknamePreference; private Preference mAddUser; private int mRemovingUserId = -1; private int mAddedUserId = 0; private boolean mAddingUser; private boolean mEnabled = true; + private boolean mCanAddUser = true; private boolean mCanAddRestrictedProfile = true; private final Object mUserLock = new Object(); @@ -212,17 +215,21 @@ public class UserSettings extends SettingsPreferenceFragment mMePreference.setSummary(R.string.user_owner); } mAddUser = findPreference(KEY_ADD_USER); + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( + Context.DEVICE_POLICY_SERVICE); + // No restricted profiles for tablets with a device owner, or phones. + if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) { + mCanAddRestrictedProfile = false; + } + // Determine if add user/profile button should be visible if (!mIsOwner || UserManager.getMaxSupportedUsers() < 2 || !UserManager.supportsMultipleUsers() || mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) { - removePreference(KEY_ADD_USER); + mCanAddUser = false; } else { mAddUser.setOnPreferenceClickListener(this); - DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( - Context.DEVICE_POLICY_SERVICE); - // No restricted profiles for tablets with a device owner, or phones. - if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) { - mCanAddRestrictedProfile = false; + // change label to only mention user, if restricted profiles are not supported + if (!mCanAddRestrictedProfile) { mAddUser.setTitle(R.string.user_add_user_menu); } } @@ -495,7 +502,7 @@ public class UserSettings extends SettingsPreferenceFragment switch (dialogId) { case DIALOG_CONFIRM_REMOVE: { Dialog dlg = - Utils.createRemoveConfirmationDialog(getActivity(), mRemovingUserId, + UserDialogs.createRemoveDialog(getActivity(), mRemovingUserId, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { removeUserNow(); @@ -712,18 +719,17 @@ public class UserSettings extends SettingsPreferenceFragment List<UserInfo> users = mUserManager.getUsers(true); final Context context = getActivity(); - mUserListCategory.removeAll(); - mUserListCategory.setOrderingAsAdded(false); - mUserListCategory.addPreference(mMePreference); - final boolean voiceCapable = Utils.isVoiceCapable(context); - final ArrayList<Integer> missingIcons = new ArrayList<Integer>(); + final ArrayList<Integer> missingIcons = new ArrayList<>(); + final ArrayList<UserPreference> userPreferences = new ArrayList<>(); + userPreferences.add(mMePreference); + for (UserInfo user : users) { if (user.isManagedProfile()) { // Managed profiles appear under Accounts Settings instead continue; } - Preference pref; + UserPreference pref; if (user.id == UserHandle.myUserId()) { pref = mMePreference; } else if (user.isGuest()) { @@ -746,7 +752,7 @@ public class UserSettings extends SettingsPreferenceFragment showDelete ? this : null); pref.setOnPreferenceClickListener(this); pref.setKey("id=" + user.id); - mUserListCategory.addPreference(pref); + userPreferences.add(pref); if (user.id == UserHandle.USER_OWNER) { pref.setSummary(R.string.user_owner); } @@ -777,48 +783,82 @@ public class UserSettings extends SettingsPreferenceFragment // Add a temporary entry for the user being created if (mAddingUser) { - Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN, - null, null); + UserPreference pref = new UserPreference(getActivity(), null, + UserPreference.USERID_UNKNOWN, null, null); pref.setEnabled(false); pref.setTitle(R.string.user_new_user_name); pref.setIcon(getEncircledDefaultIcon()); - mUserListCategory.addPreference(pref); + userPreferences.add(pref); } - boolean showGuestPreference = !mIsGuest; - // If user has DISALLOW_ADD_USER don't allow creating a guest either. - if (showGuestPreference && mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) { - showGuestPreference = false; - // If guest already exists, no user creation needed. - for (UserInfo user : users) { - if (user.isGuest()) { - showGuestPreference = true; - break; - } - } - } - if (showGuestPreference) { + if (shouldShowGuestUserPreference(users)) { // Add a virtual Guest user for guest defaults - Preference pref = new UserPreference(getActivity(), null, + UserPreference pref = new UserPreference(getActivity(), null, UserPreference.USERID_GUEST_DEFAULTS, mIsOwner && voiceCapable? this : null /* settings icon handler */, null /* delete icon handler */); pref.setTitle(R.string.user_guest); pref.setIcon(getEncircledDefaultIcon()); pref.setOnPreferenceClickListener(this); - mUserListCategory.addPreference(pref); + userPreferences.add(pref); } + // Sort list of users by serialNum + Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR); + getActivity().invalidateOptionsMenu(); // Load the icons if (missingIcons.size() > 0) { loadIconsAsync(missingIcons); } - boolean moreUsers = mUserManager.canAddMoreUsers(); - mAddUser.setEnabled(moreUsers); + + PreferenceScreen preferenceScreen = getPreferenceScreen(); + preferenceScreen.removeAll(); + + // If profiles are supported, userPreferences will be added to the category labeled + // "User & Profiles", otherwise the category is skipped and elements are added directly + // to preferenceScreen + PreferenceGroup groupToAddUsers; + if (mCanAddRestrictedProfile) { + mUserListCategory.removeAll(); + mUserListCategory.setOrder(Preference.DEFAULT_ORDER); + preferenceScreen.addPreference(mUserListCategory); + groupToAddUsers = mUserListCategory; + } else { + groupToAddUsers = preferenceScreen; + } + for (UserPreference userPreference : userPreferences) { + userPreference.setOrder(Preference.DEFAULT_ORDER); + groupToAddUsers.addPreference(userPreference); + } + + // Append Add user to the end of the list + if (mCanAddUser) { + boolean moreUsers = mUserManager.canAddMoreUsers(); + mAddUser.setEnabled(moreUsers); + mAddUser.setOrder(Preference.DEFAULT_ORDER); + preferenceScreen.addPreference(mAddUser); + } + } + + private boolean shouldShowGuestUserPreference(List<UserInfo> users) { + boolean showGuestPreference = !mIsGuest; + // If user has DISALLOW_ADD_USER don't allow creating a guest either. + if (showGuestPreference && mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) { + showGuestPreference = false; + // If guest already exists, no user creation needed. + for (UserInfo user : users) { + if (user.isGuest()) { + showGuestPreference = true; + break; + } + } + } + return showGuestPreference; } + private void loadIconsAsync(List<Integer> missingIcons) { final Resources resources = getResources(); new AsyncTask<List<Integer>, Void, Void>() { diff --git a/src/com/android/settings/voice/VoiceInputHelper.java b/src/com/android/settings/voice/VoiceInputHelper.java index 63b891a..916e0b4 100644 --- a/src/com/android/settings/voice/VoiceInputHelper.java +++ b/src/com/android/settings/voice/VoiceInputHelper.java @@ -136,10 +136,8 @@ public final class VoiceInputHelper { continue; } mAvailableInteractionInfos.add(new InteractionInfo(mContext.getPackageManager(), info)); - if (info.getRecognitionService() != null) { - interactorRecognizers.add(new ComponentName(resolveInfo.serviceInfo.packageName, - info.getRecognitionService())); - } + interactorRecognizers.add(new ComponentName(resolveInfo.serviceInfo.packageName, + info.getRecognitionService())); } Collections.sort(mAvailableInteractionInfos); diff --git a/src/com/android/settings/voice/VoiceInputSettings.java b/src/com/android/settings/voice/VoiceInputSettings.java index 262f145..bc299c2 100644 --- a/src/com/android/settings/voice/VoiceInputSettings.java +++ b/src/com/android/settings/voice/VoiceInputSettings.java @@ -146,12 +146,11 @@ public class VoiceInputSettings extends SettingsPreferenceFragment implements // Put the new value back into secure settings. Settings.Secure.putString(getActivity().getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE, key); - // Eventually we will require that an interactor always specify a recognizer - if (info.settings != null) { - Settings.Secure.putString(getActivity().getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, - info.settings.flattenToShortString()); - } + Settings.Secure.putString(getActivity().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + new ComponentName(info.service.packageName, + info.serviceInfo.getRecognitionService()) + .flattenToShortString()); return; } } diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java index a5d3658..1f5aaf4 100644 --- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java +++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java @@ -41,8 +41,9 @@ import android.util.Log; import android.widget.RemoteViews; import com.android.settings.R; -import com.android.settings.bluetooth.LocalBluetoothAdapter; -import com.android.settings.bluetooth.LocalBluetoothManager; +import com.android.settings.bluetooth.Utils; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * Provides control of power-related settings from a widget. @@ -448,7 +449,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider { @Override public int getActualState(Context context) { if (sLocalBluetoothAdapter == null) { - LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context); + LocalBluetoothManager manager = Utils.getLocalBtManager(context); if (manager == null) { return STATE_UNKNOWN; // On emulator? } diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java deleted file mode 100644 index 1bf1a5c..0000000 --- a/src/com/android/settings/wifi/AccessPoint.java +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Copyright (C) 2010 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 com.android.settings.wifi; - -import com.android.settings.R; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.StateListDrawable; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.KeyMgmt; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Bundle; -import android.preference.Preference; -import android.util.Log; -import android.util.LruCache; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import java.util.Map; - - -class AccessPoint extends Preference { - static final String TAG = "Settings.AccessPoint"; - - /** - * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels - */ - public static final int LOWER_FREQ_24GHZ = 2400; - - /** - * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels - */ - public static final int HIGHER_FREQ_24GHZ = 2500; - - /** - * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels - */ - public static final int LOWER_FREQ_5GHZ = 4900; - - /** - * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels - */ - public static final int HIGHER_FREQ_5GHZ = 5900; - - /** - * Experimental: we should be able to show the user the list of BSSIDs and bands - * for that SSID. - * For now this data is used only with Verbose Logging so as to show the band and number - * of BSSIDs on which that network is seen. - */ - public LruCache<String, ScanResult> mScanResultCache; - - - private static final String KEY_NETWORKINFO = "key_networkinfo"; - private static final String KEY_WIFIINFO = "key_wifiinfo"; - private static final String KEY_SCANRESULT = "key_scanresult"; - private static final String KEY_CONFIG = "key_config"; - - private static final int[] STATE_SECURED = { - R.attr.state_encrypted - }; - private static final int[] STATE_NONE = {}; - - private static int[] wifi_signal_attributes = { R.attr.wifi_signal }; - - /** - * These values are matched in string arrays -- changes must be kept in sync - */ - static final int SECURITY_NONE = 0; - static final int SECURITY_WEP = 1; - static final int SECURITY_PSK = 2; - static final int SECURITY_EAP = 3; - - enum PskType { - UNKNOWN, - WPA, - WPA2, - WPA_WPA2 - } - - String ssid; - String bssid; - int security; - int networkId = -1; - boolean wpsAvailable = false; - boolean showSummary = true; - - PskType pskType = PskType.UNKNOWN; - - private WifiConfiguration mConfig; - /* package */ScanResult mScanResult; - - private int mRssi = Integer.MAX_VALUE; - private long mSeen = 0; - - private WifiInfo mInfo; - private NetworkInfo mNetworkInfo; - private TextView mSummaryView; - - private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000; - private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000; - private static final int SECOND_TO_MILLI = 1000; - - static int getSecurity(WifiConfiguration config) { - if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { - return SECURITY_PSK; - } - if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || - config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { - return SECURITY_EAP; - } - return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE; - } - - private static int getSecurity(ScanResult result) { - if (result.capabilities.contains("WEP")) { - return SECURITY_WEP; - } else if (result.capabilities.contains("PSK")) { - return SECURITY_PSK; - } else if (result.capabilities.contains("EAP")) { - return SECURITY_EAP; - } - return SECURITY_NONE; - } - - public String getSecurityString(boolean concise) { - Context context = getContext(); - switch(security) { - case SECURITY_EAP: - return concise ? context.getString(R.string.wifi_security_short_eap) : - context.getString(R.string.wifi_security_eap); - case SECURITY_PSK: - switch (pskType) { - case WPA: - return concise ? context.getString(R.string.wifi_security_short_wpa) : - context.getString(R.string.wifi_security_wpa); - case WPA2: - return concise ? context.getString(R.string.wifi_security_short_wpa2) : - context.getString(R.string.wifi_security_wpa2); - case WPA_WPA2: - return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) : - context.getString(R.string.wifi_security_wpa_wpa2); - case UNKNOWN: - default: - return concise ? context.getString(R.string.wifi_security_short_psk_generic) - : context.getString(R.string.wifi_security_psk_generic); - } - case SECURITY_WEP: - return concise ? context.getString(R.string.wifi_security_short_wep) : - context.getString(R.string.wifi_security_wep); - case SECURITY_NONE: - default: - return concise ? "" : context.getString(R.string.wifi_security_none); - } - } - - private static PskType getPskType(ScanResult result) { - boolean wpa = result.capabilities.contains("WPA-PSK"); - boolean wpa2 = result.capabilities.contains("WPA2-PSK"); - if (wpa2 && wpa) { - return PskType.WPA_WPA2; - } else if (wpa2) { - return PskType.WPA2; - } else if (wpa) { - return PskType.WPA; - } else { - Log.w(TAG, "Received abnormal flag string: " + result.capabilities); - return PskType.UNKNOWN; - } - } - - AccessPoint(Context context, WifiConfiguration config) { - super(context); - loadConfig(config); - refresh(); - } - - AccessPoint(Context context, ScanResult result) { - super(context); - loadResult(result); - refresh(); - } - - AccessPoint(Context context, Bundle savedState) { - super(context); - - mConfig = savedState.getParcelable(KEY_CONFIG); - if (mConfig != null) { - loadConfig(mConfig); - } - mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT); - if (mScanResult != null) { - loadResult(mScanResult); - } - mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO); - if (savedState.containsKey(KEY_NETWORKINFO)) { - mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO); - } - update(mInfo, mNetworkInfo); - } - - public void saveWifiState(Bundle savedState) { - savedState.putParcelable(KEY_CONFIG, mConfig); - savedState.putParcelable(KEY_SCANRESULT, mScanResult); - savedState.putParcelable(KEY_WIFIINFO, mInfo); - if (mNetworkInfo != null) { - savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo); - } - } - - private void loadConfig(WifiConfiguration config) { - ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID)); - bssid = config.BSSID; - security = getSecurity(config); - networkId = config.networkId; - mConfig = config; - } - - private void loadResult(ScanResult result) { - ssid = result.SSID; - bssid = result.BSSID; - security = getSecurity(result); - wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS"); - if (security == SECURITY_PSK) - pskType = getPskType(result); - mRssi = result.level; - mScanResult = result; - if (result.seen > mSeen) { - mSeen = result.seen; - } - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - updateIcon(getLevel(), getContext()); - - mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); - mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); - - notifyChanged(); - } - - protected void updateIcon(int level, Context context) { - if (level == -1) { - setIcon(null); - } else { - Drawable drawable = getIcon(); - - if (drawable == null) { - // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then - // set the icon (drawable) to that state's drawable. - StateListDrawable sld = (StateListDrawable) context.getTheme() - .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0); - // If sld is null then we are indexing and therefore do not have access to - // (nor need to display) the drawable. - if (sld != null) { - sld.setState((security != SECURITY_NONE) ? STATE_SECURED : STATE_NONE); - drawable = sld.getCurrent(); - setIcon(drawable); - } - } - - if (drawable != null) { - drawable.setLevel(level); - } - } - } - - @Override - public int compareTo(Preference preference) { - if (!(preference instanceof AccessPoint)) { - return 1; - } - AccessPoint other = (AccessPoint) preference; - // Active one goes first. - if (isActive() && !other.isActive()) return -1; - if (!isActive() && other.isActive()) return 1; - - // Reachable one goes before unreachable one. - if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1; - if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1; - - // Configured one goes before unconfigured one. - if (networkId != WifiConfiguration.INVALID_NETWORK_ID - && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1; - if (networkId == WifiConfiguration.INVALID_NETWORK_ID - && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1; - - // Sort by signal strength. - int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi); - if (difference != 0) { - return difference; - } - // Sort by ssid. - return ssid.compareToIgnoreCase(other.ssid); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof AccessPoint)) return false; - return (this.compareTo((AccessPoint) other) == 0); - } - - @Override - public int hashCode() { - int result = 0; - if (mInfo != null) result += 13 * mInfo.hashCode(); - result += 19 * mRssi; - result += 23 * networkId; - result += 29 * ssid.hashCode(); - return result; - } - - boolean update(ScanResult result) { - if (result.seen > mSeen) { - mSeen = result.seen; - } - if (WifiSettings.mVerboseLogging > 0) { - if (mScanResultCache == null) { - mScanResultCache = new LruCache<String, ScanResult>(32); - } - mScanResultCache.put(result.BSSID, result); - } - - if (ssid.equals(result.SSID) && security == getSecurity(result)) { - if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) { - int oldLevel = getLevel(); - mRssi = result.level; - if (getLevel() != oldLevel) { - notifyChanged(); - } - } - // This flag only comes from scans, is not easily saved in config - if (security == SECURITY_PSK) { - pskType = getPskType(result); - } - mScanResult = result; - refresh(); - return true; - } - return false; - } - - /** Return whether the given {@link WifiInfo} is for this access point. */ - private boolean isInfoForThisAccessPoint(WifiInfo info) { - if (networkId != WifiConfiguration.INVALID_NETWORK_ID) { - return networkId == info.getNetworkId(); - } else { - // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID. - // (Note that we only do this if the WifiConfiguration explicitly equals INVALID). - // TODO: Handle hex string SSIDs. - return ssid.equals(removeDoubleQuotes(info.getSSID())); - } - } - - void update(WifiInfo info, NetworkInfo networkInfo) { - boolean reorder = false; - if (info != null && isInfoForThisAccessPoint(info)) { - reorder = (mInfo == null); - mRssi = info.getRssi(); - mInfo = info; - mNetworkInfo = networkInfo; - refresh(); - } else if (mInfo != null) { - reorder = true; - mInfo = null; - mNetworkInfo = null; - refresh(); - } - if (reorder) { - notifyHierarchyChanged(); - } - } - - int getLevel() { - if (mRssi == Integer.MAX_VALUE) { - return -1; - } - return WifiManager.calculateSignalLevel(mRssi, 4); - } - - WifiConfiguration getConfig() { - return mConfig; - } - - WifiInfo getInfo() { - return mInfo; - } - - NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - - DetailedState getState() { - return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null; - } - - static String removeDoubleQuotes(String string) { - int length = string.length(); - if ((length > 1) && (string.charAt(0) == '"') - && (string.charAt(length - 1) == '"')) { - return string.substring(1, length - 1); - } - return string; - } - - static String convertToQuotedString(String string) { - return "\"" + string + "\""; - } - - /** - * Shows or Hides the Summary of an AccessPoint. - * - * @param showSummary true will show the summary, false will hide the summary - */ - public void setShowSummary(boolean showSummary) { - this.showSummary = showSummary; - if (mSummaryView != null) { - mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); - } // otherwise, will be handled in onBindView. - } - - /** - * Returns the visibility status of the WifiConfiguration. - * - * @return autojoin debugging information - * TODO: use a string formatter - * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] - * For instance [-40,5/-30,2] - */ - private String getVisibilityStatus() { - StringBuilder visibility = new StringBuilder(); - StringBuilder scans24GHz = null; - StringBuilder scans5GHz = null; - String bssid = null; - - long now = System.currentTimeMillis(); - - if (mInfo != null) { - bssid = mInfo.getBSSID(); - if (bssid != null) { - visibility.append(" ").append(bssid); - } - visibility.append(" rssi=").append(mInfo.getRssi()); - visibility.append(" "); - visibility.append(" score=").append(mInfo.score); - visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate)); - visibility.append(String.format("%.1f,", mInfo.txRetriesRate)); - visibility.append(String.format("%.1f ", mInfo.txBadRate)); - visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate)); - } - - if (mScanResultCache != null) { - int rssi5 = WifiConfiguration.INVALID_RSSI; - int rssi24 = WifiConfiguration.INVALID_RSSI; - int num5 = 0; - int num24 = 0; - int numBlackListed = 0; - int n24 = 0; // Number scan results we included in the string - int n5 = 0; // Number scan results we included in the string - Map<String, ScanResult> list = mScanResultCache.snapshot(); - // TODO: sort list by RSSI or age - for (ScanResult result : list.values()) { - if (result.seen == 0) - continue; - - if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++; - - if (result.frequency >= LOWER_FREQ_5GHZ - && result.frequency <= HIGHER_FREQ_5GHZ) { - // Strictly speaking: [4915, 5825] - // number of known BSSID on 5GHz band - num5 = num5 + 1; - } else if (result.frequency >= LOWER_FREQ_24GHZ - && result.frequency <= HIGHER_FREQ_24GHZ) { - // Strictly speaking: [2412, 2482] - // number of known BSSID on 2.4Ghz band - num24 = num24 + 1; - } - - // Ignore results seen, older than 20 seconds - if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue; - - if (result.frequency >= LOWER_FREQ_5GHZ - && result.frequency <= HIGHER_FREQ_5GHZ) { - if (result.level > rssi5) { - rssi5 = result.level; - } - if (n5 < 4) { - if (scans5GHz == null) scans5GHz = new StringBuilder(); - scans5GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*"); - scans5GHz.append("=").append(result.frequency); - scans5GHz.append(",").append(result.level); - if (result.autoJoinStatus != 0) { - scans5GHz.append(",st=").append(result.autoJoinStatus); - } - if (result.numIpConfigFailures != 0) { - scans5GHz.append(",ipf=").append(result.numIpConfigFailures); - } - scans5GHz.append("}"); - n5++; - } - } else if (result.frequency >= LOWER_FREQ_24GHZ - && result.frequency <= HIGHER_FREQ_24GHZ) { - if (result.level > rssi24) { - rssi24 = result.level; - } - if (n24 < 4) { - if (scans24GHz == null) scans24GHz = new StringBuilder(); - scans24GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*"); - scans24GHz.append("=").append(result.frequency); - scans24GHz.append(",").append(result.level); - if (result.autoJoinStatus != 0) { - scans24GHz.append(",st=").append(result.autoJoinStatus); - } - if (result.numIpConfigFailures != 0) { - scans24GHz.append(",ipf=").append(result.numIpConfigFailures); - } - scans24GHz.append("}"); - n24++; - } - } - } - visibility.append(" ["); - if (num24 > 0) { - visibility.append("(").append(num24).append(")"); - if (n24 <= 4) { - if (scans24GHz != null) { - visibility.append(scans24GHz.toString()); - } - } else { - visibility.append("max=").append(rssi24); - if (scans24GHz != null) { - visibility.append(",").append(scans24GHz.toString()); - } - } - } - visibility.append(";"); - if (num5 > 0) { - visibility.append("(").append(num5).append(")"); - if (n5 <= 4) { - if (scans5GHz != null) { - visibility.append(scans5GHz.toString()); - } - } else { - visibility.append("max=").append(rssi5); - if (scans5GHz != null) { - visibility.append(",").append(scans5GHz.toString()); - } - } - } - if (numBlackListed > 0) - visibility.append("!").append(numBlackListed); - visibility.append("]"); - } else { - if (mRssi != Integer.MAX_VALUE) { - visibility.append(" rssi="); - visibility.append(mRssi); - if (mScanResult != null) { - visibility.append(", f="); - visibility.append(mScanResult.frequency); - } - } - } - - return visibility.toString(); - } - - /** - * Return whether this is the active connection. - * For ephemeral connections (networkId is invalid), this returns false if the network is - * disconnected. - */ - boolean isActive() { - return mNetworkInfo != null && - (networkId != WifiConfiguration.INVALID_NETWORK_ID || - mNetworkInfo.getState() != State.DISCONNECTED); - } - - /** - * Updates the title and summary; may indirectly call notifyChanged(). - */ - private void refresh() { - setTitle(ssid); - - final Context context = getContext(); - updateIcon(getLevel(), context); - - // Force new summary - setSummary(null); - - // Update to new summary - StringBuilder summary = new StringBuilder(); - - if (isActive()) { // This is the active connection - summary.append(Summary.get(context, getState(), - networkId == WifiConfiguration.INVALID_NETWORK_ID)); - } else if (mConfig != null - && mConfig.hasNoInternetAccess()) { - summary.append(context.getString(R.string.wifi_no_internet)); - } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED && - mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON) - || mConfig.autoJoinStatus - >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { - if (mConfig.autoJoinStatus - >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { - if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) { - summary.append(context.getString(R.string.wifi_disabled_network_failure)); - } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) { - summary.append(context.getString(R.string.wifi_disabled_password_failure)); - } else { - summary.append(context.getString(R.string.wifi_disabled_wifi_failure)); - } - } else { - switch (mConfig.disableReason) { - case WifiConfiguration.DISABLED_AUTH_FAILURE: - summary.append(context.getString(R.string.wifi_disabled_password_failure)); - break; - case WifiConfiguration.DISABLED_DHCP_FAILURE: - case WifiConfiguration.DISABLED_DNS_FAILURE: - summary.append(context.getString(R.string.wifi_disabled_network_failure)); - break; - case WifiConfiguration.DISABLED_UNKNOWN_REASON: - case WifiConfiguration.DISABLED_ASSOCIATION_REJECT: - summary.append(context.getString(R.string.wifi_disabled_generic)); - break; - } - } - } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range - summary.append(context.getString(R.string.wifi_not_in_range)); - } else { // In range, not disabled. - if (mConfig != null) { // Is saved network - summary.append(context.getString(R.string.wifi_remembered)); - } - } - - if (WifiSettings.mVerboseLogging > 0) { - // Add RSSI/band information for this config, what was seen up to 6 seconds ago - // verbose WiFi Logging is only turned on thru developers settings - if (mInfo != null && mNetworkInfo != null) { // This is the active connection - summary.append(" f=" + Integer.toString(mInfo.getFrequency())); - } - summary.append(" " + getVisibilityStatus()); - if (mConfig != null && mConfig.autoJoinStatus > 0) { - summary.append(" (" + mConfig.autoJoinStatus); - if (mConfig.blackListTimestamp > 0) { - long now = System.currentTimeMillis(); - long diff = (now - mConfig.blackListTimestamp)/1000; - long sec = diff%60; //seconds - long min = (diff/60)%60; //minutes - long hour = (min/60)%60; //hours - summary.append(", "); - if (hour > 0) summary.append(Long.toString(hour) + "h "); - summary.append( Long.toString(min) + "m "); - summary.append( Long.toString(sec) + "s "); - } - summary.append(")"); - } - if (mConfig != null && mConfig.numIpConfigFailures > 0) { - summary.append(" ipf=").append(mConfig.numIpConfigFailures); - } - if (mConfig != null && mConfig.numConnectionFailures > 0) { - summary.append(" cf=").append(mConfig.numConnectionFailures); - } - if (mConfig != null && mConfig.numAuthFailures > 0) { - summary.append(" authf=").append(mConfig.numAuthFailures); - } - if (mConfig != null && mConfig.numNoInternetAccessReports > 0) { - summary.append(" noInt=").append(mConfig.numNoInternetAccessReports); - } - } - - if (summary.length() > 0) { - setSummary(summary.toString()); - setShowSummary(true); - } else { - setShowSummary(false); - } - } - - /** - * Generate and save a default wifiConfiguration with common values. - * Can only be called for unsecured networks. - * @hide - */ - protected void generateOpenNetworkConfig() { - if (security != SECURITY_NONE) - throw new IllegalStateException(); - if (mConfig != null) - return; - mConfig = new WifiConfiguration(); - mConfig.SSID = AccessPoint.convertToQuotedString(ssid); - mConfig.allowedKeyManagement.set(KeyMgmt.NONE); - } -} diff --git a/src/com/android/settings/wifi/AccessPointPreference.java b/src/com/android/settings/wifi/AccessPointPreference.java new file mode 100644 index 0000000..3975434 --- /dev/null +++ b/src/com/android/settings/wifi/AccessPointPreference.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2015 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 com.android.settings.wifi; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; +import android.net.wifi.WifiConfiguration; +import android.preference.Preference; +import android.view.View; +import android.widget.TextView; + +import com.android.settings.R; +import com.android.settingslib.wifi.AccessPoint; + +public class AccessPointPreference extends Preference { + + private static final int[] STATE_SECURED = { + R.attr.state_encrypted + }; + private static final int[] STATE_NONE = {}; + + private static int[] wifi_signal_attributes = { R.attr.wifi_signal }; + + private TextView mSummaryView; + private boolean showSummary = true; + private AccessPoint mAccessPoint; + + public AccessPointPreference(AccessPoint accessPoint, Context context) { + super(context); + mAccessPoint = accessPoint; + mAccessPoint.setTag(this); + refresh(); + } + + public AccessPoint getAccessPoint() { + return mAccessPoint; + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + updateIcon(mAccessPoint.getLevel(), getContext()); + + mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); + mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); + + notifyChanged(); + } + + public void showAppIcon() { + PackageManager pm = getContext().getPackageManager(); + String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID); + WifiConfiguration mConfig = mAccessPoint.getConfig(); + + Drawable drawable = pm.getDefaultActivityIcon(); + if (mConfig == null) { + drawable.setAlpha(0); + } else if (mConfig.creatorName.equals(systemName)) { + drawable = getContext().getApplicationInfo().loadIcon(pm); + } else { + try { + drawable = pm.getApplicationIcon(mConfig.creatorName); + } catch (NameNotFoundException nnfe) { + // use default app icon + } + } + + setIcon(drawable); + } + + protected void updateIcon(int level, Context context) { + if (level == -1) { + setIcon(null); + } else { + Drawable drawable = getIcon(); + + if (drawable == null) { + // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then + // set the icon (drawable) to that state's drawable. + StateListDrawable sld = (StateListDrawable) context.getTheme() + .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0); + // If sld is null then we are indexing and therefore do not have access to + // (nor need to display) the drawable. + if (sld != null) { + sld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) + ? STATE_SECURED + : STATE_NONE); + drawable = sld.getCurrent(); + setIcon(drawable); + } + } + + if (drawable != null) { + drawable.setLevel(level); + } + } + } + + /** + * Shows or Hides the Summary of an AccessPoint. + * + * @param showSummary true will show the summary, false will hide the summary + */ + public void setShowSummary(boolean showSummary) { + this.showSummary = showSummary; + if (mSummaryView != null) { + mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); + } // otherwise, will be handled in onBindView. + } + + /** + * Updates the title and summary; may indirectly call notifyChanged(). + */ + public void refresh() { + setTitle(mAccessPoint.getSsid()); + + final Context context = getContext(); + updateIcon(mAccessPoint.getLevel(), context); + + // Force new summary + setSummary(null); + + String summary = mAccessPoint.getSummary(); + if (summary.length() > 0) { + setSummary(summary); + setShowSummary(true); + } else { + setShowSummary(false); + } + } + + public void onLevelChanged() { + notifyChanged(); + } + +} diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java index bea720c..e92bda7 100644 --- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java +++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java @@ -20,28 +20,22 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; - -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; - import android.util.Log; -import android.view.View; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.wifi.AccessPoint; +import com.android.settingslib.wifi.WifiTracker; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * UI to manage saved networks/access points. @@ -88,14 +82,17 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment PreferenceScreen preferenceScreen = getPreferenceScreen(); final Context context = getActivity(); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - final List<AccessPoint> accessPoints = constructSavedAccessPoints(context, mWifiManager); + final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context, true, + false); preferenceScreen.removeAll(); final int accessPointsSize = accessPoints.size(); for (int i = 0; i < accessPointsSize; ++i){ - preferenceScreen.addPreference(accessPoints.get(i)); + AccessPointPreference preference = new AccessPointPreference(accessPoints.get(i), + context); + preference.setShowSummary(false); + preferenceScreen.addPreference(preference); } if(getPreferenceScreen().getPreferenceCount() < 1) { @@ -103,62 +100,14 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment } } - private static List<AccessPoint> constructSavedAccessPoints(Context context, - WifiManager wifiManager){ - List<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); - Map<String, List<ScanResult>> resultsMap = new HashMap<String, List<ScanResult>>(); - - final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks(); - final List<ScanResult> scanResults = wifiManager.getScanResults(); - - if (configs != null) { - //Construct a Map for quick searching of a wifi network via ssid. - final int scanResultsSize = scanResults.size(); - for (int i = 0; i < scanResultsSize; ++i){ - final ScanResult result = scanResults.get(i); - List<ScanResult> res = resultsMap.get(result.SSID); - - if(res == null){ - res = new ArrayList<ScanResult>(); - resultsMap.put(result.SSID, res); - } - - res.add(result); - } - - final int configsSize = configs.size(); - for (int i = 0; i < configsSize; ++i){ - WifiConfiguration config = configs.get(i); - if (config.selfAdded && config.numAssociation == 0) { - continue; - } - AccessPoint accessPoint = new AccessPoint(context, config); - final List<ScanResult> results = resultsMap.get(accessPoint.ssid); - - accessPoint.setShowSummary(false); - if(results != null){ - final int resultsSize = results.size(); - for (int j = 0; j < resultsSize; ++j){ - accessPoint.update(results.get(j)); - accessPoint.setIcon(null); - } - } - - accessPoints.add(accessPoint); - } - } - - return accessPoints; - } - - private void showDialog(AccessPoint accessPoint, boolean edit) { + private void showDialog(AccessPointPreference accessPoint, boolean edit) { if (mDialog != null) { removeDialog(WifiSettings.WIFI_DIALOG_ID); mDialog = null; } // Save the access point and edit mode - mDlgAccessPoint = accessPoint; + mDlgAccessPoint = accessPoint.getAccessPoint(); showDialog(WifiSettings.WIFI_DIALOG_ID); } @@ -198,16 +147,16 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment @Override public void onClick(DialogInterface dialogInterface, int button) { if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { - mWifiManager.forget(mSelectedAccessPoint.networkId, null); - getPreferenceScreen().removePreference(mSelectedAccessPoint); + mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, null); + getPreferenceScreen().removePreference((Preference) mSelectedAccessPoint.getTag()); mSelectedAccessPoint = null; } } @Override public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { - if (preference instanceof AccessPoint) { - showDialog((AccessPoint) preference, false); + if (preference instanceof AccessPointPreference) { + showDialog((AccessPointPreference) preference, false); return true; } else{ return super.onPreferenceTreeClick(screen, preference); @@ -233,15 +182,13 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment result.add(data); // Add available Wi-Fi access points - WifiManager wifiManager = - (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - final List<AccessPoint> accessPoints = - constructSavedAccessPoints(context, wifiManager); + final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context, + true, false); final int accessPointsSize = accessPoints.size(); for (int i = 0; i < accessPointsSize; ++i){ data = new SearchIndexableRaw(context); - data.title = accessPoints.get(i).getTitle().toString(); + data.title = accessPoints.get(i).getSsid(); data.screenTitle = title; data.enabled = enabled; result.add(data); diff --git a/src/com/android/settings/wifi/Summary.java b/src/com/android/settings/wifi/Summary.java deleted file mode 100644 index 123f64a..0000000 --- a/src/com/android/settings/wifi/Summary.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010 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 com.android.settings.wifi; - -import com.android.settings.R; - -import android.content.Context; -import android.net.NetworkInfo.DetailedState; - -class Summary { - static String get(Context context, String ssid, DetailedState state, boolean isEphemeral) { - if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) { - // Special case for connected + ephemeral networks. - return context.getString(R.string.connected_via_wfa); - } - - String[] formats = context.getResources().getStringArray((ssid == null) - ? R.array.wifi_status : R.array.wifi_status_with_ssid); - int index = state.ordinal(); - - if (index >= formats.length || formats[index].length() == 0) { - return null; - } - return String.format(formats[index], ssid); - } - - static String get(Context context, DetailedState state, boolean isEphemeral) { - return get(context, null, state, isEphemeral); - } -} diff --git a/src/com/android/settings/wifi/WifiApEnabler.java b/src/com/android/settings/wifi/WifiApEnabler.java index 6aecf1f..bf2fa38 100644 --- a/src/com/android/settings/wifi/WifiApEnabler.java +++ b/src/com/android/settings/wifi/WifiApEnabler.java @@ -16,28 +16,20 @@ package com.android.settings.wifi; -import com.android.settings.R; -import com.android.settings.WirelessSettings; - -import java.util.ArrayList; - -import android.app.AlertDialog; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.preference.SwitchPreference; import android.provider.Settings; -import android.text.TextUtils; -import android.util.Log; -import android.widget.Toast; + +import com.android.settings.R; +import com.android.settingslib.TetherUtil; + +import java.util.ArrayList; public class WifiApEnabler { private final Context mContext; @@ -74,10 +66,8 @@ public class WifiApEnabler { public WifiApEnabler(Context context, SwitchPreference switchPreference) { mContext = context; mSwitch = switchPreference; - mOriginalSummary = switchPreference != null ? switchPreference.getSummary() : ""; - if (switchPreference != null) { - switchPreference.setPersistent(false); - } + mOriginalSummary = switchPreference.getSummary(); + switchPreference.setPersistent(false); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); @@ -110,43 +100,13 @@ public class WifiApEnabler { } public void setSoftapEnabled(boolean enable) { - final ContentResolver cr = mContext.getContentResolver(); - /** - * Disable Wifi if enabling tethering - */ - int wifiState = mWifiManager.getWifiState(); - if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) || - (wifiState == WifiManager.WIFI_STATE_ENABLED))) { - mWifiManager.setWifiEnabled(false); - Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1); - } - - if (mWifiManager.setWifiApEnabled(null, enable)) { - if (mSwitch != null) { - /* Disable here, enabled on receiving success broadcast */ - mSwitch.setEnabled(false); - } + if (TetherUtil.setWifiTethering(enable, mContext)) { + /* Disable here, enabled on receiving success broadcast */ + mSwitch.setEnabled(false); } else { - if (mSwitch != null) { - mSwitch.setSummary(R.string.wifi_error); - } + mSwitch.setSummary(R.string.wifi_error); } - /** - * If needed, restore Wifi on tether disable - */ - if (!enable) { - int wifiSavedState = 0; - try { - wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE); - } catch (Settings.SettingNotFoundException e) { - ; - } - if (wifiSavedState == 1) { - mWifiManager.setWifiEnabled(true); - Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0); - } - } } public void updateConfigSummary(WifiConfiguration wifiConfig) { diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java index 5462d26..e244b7f 100644 --- a/src/com/android/settings/wifi/WifiConfigController.java +++ b/src/com/android/settings/wifi/WifiConfigController.java @@ -16,9 +16,6 @@ package com.android.settings.wifi; -import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; - -import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; import android.net.IpConfiguration; @@ -28,7 +25,6 @@ import android.net.LinkAddress; import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.net.ProxyInfo; -import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.net.Uri; import android.net.wifi.WifiConfiguration; @@ -39,7 +35,6 @@ import android.net.wifi.WifiEnterpriseConfig.Eap; import android.net.wifi.WifiEnterpriseConfig.Phase2; import android.net.wifi.WifiInfo; import android.os.Handler; -import android.os.UserHandle; import android.security.Credentials; import android.security.KeyStore; import android.text.Editable; @@ -61,6 +56,7 @@ import android.widget.TextView; import com.android.settings.ProxySelector; import com.android.settings.R; +import com.android.settingslib.wifi.AccessPoint; import java.net.InetAddress; import java.net.Inet4Address; @@ -103,9 +99,6 @@ public class WifiConfigController implements TextWatcher, /* Full list of phase2 methods */ private final ArrayAdapter<String> PHASE2_FULL_ADAPTER; - // True when this instance is used in SetupWizard XL context. - private final boolean mInXlSetupWizard; - private final Handler mTextViewChangedHandler; // e.g. AccessPoint.SECURITY_NONE @@ -152,12 +145,11 @@ public class WifiConfigController implements TextWatcher, public WifiConfigController( WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit) { mConfigUi = parent; - mInXlSetupWizard = (parent instanceof WifiConfigUiForSetupWizardXL); mView = view; mAccessPoint = accessPoint; mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE : - accessPoint.security; + accessPoint.getSecurity(); mEdit = edit; mTextViewChangedHandler = new Handler(); @@ -188,18 +180,7 @@ public class WifiConfigController implements TextWatcher, mSsidView.addTextChangedListener(this); mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security)); mSecuritySpinner.setOnItemSelectedListener(this); - if (mInXlSetupWizard) { - mView.findViewById(R.id.type_ssid).setVisibility(View.VISIBLE); - mView.findViewById(R.id.type_security).setVisibility(View.VISIBLE); - // We want custom layout. The content must be same as the other cases. - - ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, - R.layout.wifi_setup_custom_list_item_1, android.R.id.text1, - res.getStringArray(R.array.wifi_security_no_eap)); - mSecuritySpinner.setAdapter(adapter); - } else { - mView.findViewById(R.id.type).setVisibility(View.VISIBLE); - } + mView.findViewById(R.id.type).setVisibility(View.VISIBLE); showIpConfigFields(); showProxyFields(); @@ -210,12 +191,12 @@ public class WifiConfigController implements TextWatcher, mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); } else { - mConfigUi.setTitle(mAccessPoint.ssid); + mConfigUi.setTitle(mAccessPoint.getSsid()); ViewGroup group = (ViewGroup) mView.findViewById(R.id.info); boolean showAdvancedFields = false; - if (mAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mAccessPoint.isSaved()) { WifiConfiguration config = mAccessPoint.getConfig(); if (config.getIpAssignment() == IpAssignment.STATIC) { mIpSettingsSpinner.setSelection(STATIC_IP); @@ -242,7 +223,7 @@ public class WifiConfigController implements TextWatcher, } } - if ((mAccessPoint.networkId == INVALID_NETWORK_ID && !mAccessPoint.isActive()) + if ((!mAccessPoint.isSaved() && !mAccessPoint.isActive()) || mEdit) { showSecurityFields(); showIpConfigFields(); @@ -259,16 +240,15 @@ public class WifiConfigController implements TextWatcher, if (mEdit) { mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); } else { - final DetailedState state = mAccessPoint.getState(); + final DetailedState state = mAccessPoint.getDetailedState(); final String signalLevel = getSignalString(); if (state == null && signalLevel != null) { mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect)); } else { if (state != null) { - addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(), - state, mAccessPoint.networkId == - WifiConfiguration.INVALID_NETWORK_ID)); + addRow(group, R.string.wifi_status, AccessPoint.getSummary( + mConfigUi.getContext(), state, !mAccessPoint.isSaved())); } if (signalLevel != null) { @@ -302,15 +282,14 @@ public class WifiConfigController implements TextWatcher, addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false)); mView.findViewById(R.id.ip_fields).setVisibility(View.GONE); } - if ((mAccessPoint.networkId != INVALID_NETWORK_ID || mAccessPoint.isActive()) - && ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) { + if (mAccessPoint.isSaved() || mAccessPoint.isActive()) { mConfigUi.setForgetButton(res.getString(R.string.wifi_forget)); } } } if ((mEdit) || (mAccessPoint != null - && mAccessPoint.getState() == null && mAccessPoint.getLevel() != -1)){ + && mAccessPoint.getDetailedState() == null && mAccessPoint.getLevel() != -1)){ mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel)); }else{ mConfigUi.setCancelButton(res.getString(R.string.wifi_display_options_done)); @@ -355,7 +334,7 @@ public class WifiConfigController implements TextWatcher, } if ((mSsidView != null && mSsidView.length() == 0) || - ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) && + ((mAccessPoint == null || !mAccessPoint.isSaved()) && passwordInvalid)) { enabled = false; } else { @@ -369,7 +348,7 @@ public class WifiConfigController implements TextWatcher, } /* package */ WifiConfiguration getConfig() { - if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) { + if (mAccessPoint != null && mAccessPoint.isSaved() && !mEdit) { return null; } @@ -380,11 +359,11 @@ public class WifiConfigController implements TextWatcher, mSsidView.getText().toString()); // If the user adds a network manually, assume that it is hidden. config.hiddenSSID = true; - } else if (mAccessPoint.networkId == INVALID_NETWORK_ID) { + } else if (!mAccessPoint.isSaved()) { config.SSID = AccessPoint.convertToQuotedString( - mAccessPoint.ssid); + mAccessPoint.getSsid()); } else { - config.networkId = mAccessPoint.networkId; + config.networkId = mAccessPoint.getConfig().networkId; } switch (mAccessPointSecurity) { @@ -611,13 +590,6 @@ public class WifiConfigController implements TextWatcher, } private void showSecurityFields() { - if (mInXlSetupWizard) { - // Note: XL SetupWizard won't hide "EAP" settings here. - if (!((WifiSettingsForSetupWizardXL)mConfigUi.getContext()).initSecurityFields(mView, - mAccessPointSecurity)) { - return; - } - } if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) { mView.findViewById(R.id.security_fields).setVisibility(View.GONE); return; @@ -630,7 +602,7 @@ public class WifiConfigController implements TextWatcher, ((CheckBox) mView.findViewById(R.id.show_password)) .setOnCheckedChangeListener(this); - if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mAccessPoint != null && mAccessPoint.isSaved()) { mPasswordView.setHint(R.string.wifi_unchanged); } } @@ -654,7 +626,7 @@ public class WifiConfigController implements TextWatcher, loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY); // Modifying an existing network - if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mAccessPoint != null && mAccessPoint.isSaved()) { WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig; int eapMethod = enterpriseConfig.getEapMethod(); int phase2Method = enterpriseConfig.getPhase2Method(); @@ -796,7 +768,7 @@ public class WifiConfigController implements TextWatcher, mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE); - if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mAccessPoint != null && mAccessPoint.isSaved()) { config = mAccessPoint.getConfig(); } @@ -848,7 +820,7 @@ public class WifiConfigController implements TextWatcher, mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE); - if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mAccessPoint != null && mAccessPoint.isSaved()) { config = mAccessPoint.getConfig(); } diff --git a/src/com/android/settings/wifi/WifiConfigUiBase.java b/src/com/android/settings/wifi/WifiConfigUiBase.java index 11dcc00..a0f67ab 100644 --- a/src/com/android/settings/wifi/WifiConfigUiBase.java +++ b/src/com/android/settings/wifi/WifiConfigUiBase.java @@ -21,8 +21,7 @@ import android.view.LayoutInflater; import android.widget.Button; /** - * Foundation interface glues between Activities and UIs like - * {@link WifiDialog} or {@link WifiConfigUiForSetupWizardXL}. + * Foundation interface glues between Activities and UIs like {@link WifiDialog}. */ public interface WifiConfigUiBase { public Context getContext(); diff --git a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java b/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java deleted file mode 100644 index 440e694..0000000 --- a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 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 com.android.settings.wifi; - -import com.android.settings.R; - -import android.content.Context; -import android.os.Handler; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnFocusChangeListener; -import android.view.ViewGroup; -import android.view.inputmethod.InputMethodManager; -import android.widget.Button; -import android.widget.EditText; - -/** - * Shows simplified UI for configuring a wifi network. Used only in SetupWizard for XLarge - * screen. - */ -public class WifiConfigUiForSetupWizardXL implements WifiConfigUiBase, OnFocusChangeListener { - private static final String TAG = "SetupWizard"; - - private Button mConnectButton; - private Button mCancelButton; - - private final WifiSettingsForSetupWizardXL mActivity; - private View mView; - private WifiConfigController mController; - private AccessPoint mAccessPoint; - private boolean mEdit; - private Handler mHandler = new Handler(); - - private final InputMethodManager mInputMethodManager; - - private LayoutInflater mInflater; - - /** - * @param activity Activity which creates this object. - * @param parent Parent ViewGroup (typically some layout) holding a view object created by - * this object - * @param accessPoint target AccessPoint to be configured. - * @param edit - */ - public WifiConfigUiForSetupWizardXL( - WifiSettingsForSetupWizardXL activity, ViewGroup parent, - AccessPoint accessPoint, boolean edit) { - mActivity = activity; - mConnectButton = (Button)activity.findViewById(R.id.wifi_setup_connect); - mCancelButton = (Button)activity.findViewById(R.id.wifi_setup_cancel); - mAccessPoint = accessPoint; - mEdit = edit; - mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mView = mInflater.inflate(R.layout.wifi_config_ui_for_setup_wizard, parent, true); - mController = new WifiConfigController(this, mView, mAccessPoint, edit); - - mInputMethodManager = (InputMethodManager) - activity.getSystemService(Context.INPUT_METHOD_SERVICE); - - if (mView.findViewById(R.id.security_fields).getVisibility() == View.VISIBLE) { - requestFocusAndShowKeyboard(R.id.password); - } else if (mView.findViewById(R.id.type_ssid).getVisibility() == View.VISIBLE) { - // Add Network flow. - requestFocusAndShowKeyboard(R.id.ssid); - } - } - - /** - * @param editViewId must be EditView - */ - public void requestFocusAndShowKeyboard(int editViewId) { - // Set Focus to password View. - final View viewToBeFocused = mView.findViewById(editViewId); - if (viewToBeFocused == null) { - Log.w(TAG, "password field to be focused not found."); - } else if (!(viewToBeFocused instanceof EditText)) { - Log.w(TAG, "password field is not EditText"); - } else { - if (viewToBeFocused.isFocused()) { - Log.i(TAG, "Already focused"); - if (!mInputMethodManager.showSoftInput(viewToBeFocused, 0)) { - Log.w(TAG, "Failed to show SoftInput"); - } - } else { - // After acquiring the focus, we show software keyboard. - viewToBeFocused.setOnFocusChangeListener(this); - final boolean requestFocusResult = viewToBeFocused.requestFocus(); - Log.i(TAG, String.format("Focus request: %s", - (requestFocusResult ? "successful" : "failed"))); - if (!requestFocusResult) { - viewToBeFocused.setOnFocusChangeListener(null); - } - } - } - } - - public View getView() { - return mView; - } - - public AccessPoint getAccessPoint() { - return mAccessPoint; - } - - @Override - public WifiConfigController getController() { - return mController; - } - - @Override - public boolean isEdit() { - return mEdit; - } - - @Override - public LayoutInflater getLayoutInflater() { - return mInflater; - } - - @Override - public Button getSubmitButton() { - return mConnectButton; - } - - @Override - public Button getForgetButton() { - return null; - } - - @Override - public Button getCancelButton() { - return mCancelButton; - } - - @Override - public void setSubmitButton(CharSequence text) { - mConnectButton.setVisibility(View.VISIBLE); - mConnectButton.setText(text); - } - - @Override - public void setForgetButton(CharSequence text) { - // In XL setup screen, we won't show Forget button for simplifying the UI. - } - - @Override - public void setCancelButton(CharSequence text) { - mCancelButton.setVisibility(View.VISIBLE); - // We don't want "cancel" label given from caller. - // mCancelButton.setText(text); - } - - @Override - public Context getContext() { - return mActivity; - } - - @Override - public void setTitle(int id) { - Log.d(TAG, "Ignoring setTitle"); - } - - @Override - public void setTitle(CharSequence title) { - Log.d(TAG, "Ignoring setTitle"); - } - - private class FocusRunnable implements Runnable { - final View mViewToBeFocused; - public FocusRunnable(View viewToBeFocused) { - mViewToBeFocused = viewToBeFocused; - } - - @Override - public void run() { - // mInputMethodManager.focusIn(mViewToBeFocused); - final boolean showSoftInputResult = - mInputMethodManager.showSoftInput(mViewToBeFocused, 0); - if (showSoftInputResult) { - mActivity.setPaddingVisibility(View.GONE); - } else { - Log.w(TAG, "Failed to show software keyboard "); - } - } - } - - @Override - public void onFocusChange(View view, boolean hasFocus) { - view.setOnFocusChangeListener(null); - if (hasFocus) { - mHandler.post(new FocusRunnable(view)); - } - } -}
\ No newline at end of file diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java index 942c5dd..1f03fe3 100644 --- a/src/com/android/settings/wifi/WifiDialog.java +++ b/src/com/android/settings/wifi/WifiDialog.java @@ -17,6 +17,7 @@ package com.android.settings.wifi; import com.android.settings.R; +import com.android.settingslib.wifi.AccessPoint; import android.app.AlertDialog; import android.content.Context; diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java index 0952941..754dbaa 100644 --- a/src/com/android/settings/wifi/WifiEnabler.java +++ b/src/com/android/settings/wifi/WifiEnabler.java @@ -31,9 +31,9 @@ import android.widget.Switch; import android.widget.Toast; import com.android.settings.R; -import com.android.settings.WirelessSettings; import com.android.settings.search.Index; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.WirelessUtils; import java.util.concurrent.atomic.AtomicBoolean; @@ -196,7 +196,7 @@ public class WifiEnabler implements SwitchBar.OnSwitchChangeListener { return; } // Show toast message if Wi-Fi is not allowed in airplane mode - if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) { + if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) { Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); // Reset switch to off. No infinite check/listenenr loop. mSwitchBar.setChecked(false); diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 54ebc6d..a4ecf0e 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -18,32 +18,22 @@ package com.android.settings.wifi; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; import static android.os.UserManager.DISALLOW_CONFIG_WIFI; - import android.app.Activity; -import android.app.ActivityManager; import android.app.Dialog; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.content.res.TypedArray; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; -import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WpsInfo; import android.nfc.NfcAdapter; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.UserHandle; import android.preference.Preference; import android.preference.PreferenceScreen; import android.util.Log; @@ -63,13 +53,13 @@ import com.android.settings.SettingsActivity; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.wifi.AccessPoint; +import com.android.settingslib.wifi.AccessPoint.AccessPointListener; +import com.android.settingslib.wifi.WifiTracker; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; /** * Two types of UI are provided here. @@ -80,7 +70,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * and menus. */ public class WifiSettings extends RestrictedSettingsFragment - implements DialogInterface.OnClickListener, Indexable { + implements DialogInterface.OnClickListener, Indexable, WifiTracker.WifiListener, + AccessPointListener { private static final String TAG = "WifiSettings"; @@ -94,26 +85,20 @@ public class WifiSettings extends RestrictedSettingsFragment private static final int MENU_ID_FORGET = Menu.FIRST + 7; private static final int MENU_ID_MODIFY = Menu.FIRST + 8; private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9; + private static final int MENU_ID_APPS = Menu.FIRST + 10; public static final int WIFI_DIALOG_ID = 1; /* package */ static final int WPS_PBC_DIALOG_ID = 2; private static final int WPS_PIN_DIALOG_ID = 3; private static final int WRITE_NFC_DIALOG_ID = 6; - // Combo scans can take 5-6s to complete - set to 10s. - private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000; - // Instance state keys private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode"; private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; private static boolean savedNetworksExist; - private final IntentFilter mFilter; - private final BroadcastReceiver mReceiver; - private final Scanner mScanner; - - /* package */ WifiManager mWifiManager; + protected WifiManager mWifiManager; private WifiManager.ActionListener mConnectListener; private WifiManager.ActionListener mSaveListener; private WifiManager.ActionListener mForgetListener; @@ -122,16 +107,14 @@ public class WifiSettings extends RestrictedSettingsFragment // An access point being editted is stored here. private AccessPoint mSelectedAccessPoint; - private NetworkInfo mLastNetworkInfo; - private WifiInfo mLastInfo; - - private final AtomicBoolean mConnected = new AtomicBoolean(false); - private WifiDialog mDialog; private WriteWifiConfigToNfcDialog mWifiToNfcDialog; private TextView mEmptyView; + private boolean showAppIcons = false; + private MenuItem showAppMenuItem = null; + // this boolean extra specifies whether to disable the Next button when not connected. Used by // account creation outside of setup wizard. private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; @@ -147,98 +130,20 @@ public class WifiSettings extends RestrictedSettingsFragment private AccessPoint mDlgAccessPoint; private Bundle mAccessPointSavedState; - /** verbose logging flag. this flag is set thru developer debugging options - * and used so as to assist with in-the-field WiFi connectivity debugging */ - public static int mVerboseLogging = 0; + private WifiTracker mWifiTracker; /* End of "used in Wifi Setup context" */ - /** A restricted multimap for use in constructAccessPoints */ - private static class Multimap<K,V> { - private final HashMap<K,List<V>> store = new HashMap<K,List<V>>(); - /** retrieve a non-null list of values with key K */ - List<V> getAll(K key) { - List<V> values = store.get(key); - return values != null ? values : Collections.<V>emptyList(); - } - - void put(K key, V val) { - List<V> curVals = store.get(key); - if (curVals == null) { - curVals = new ArrayList<V>(3); - store.put(key, curVals); - } - curVals.add(val); - } - } - - private static class Scanner extends Handler { - private int mRetry = 0; - private WifiSettings mWifiSettings = null; - - Scanner(WifiSettings wifiSettings) { - mWifiSettings = wifiSettings; - } - - void resume() { - if (!hasMessages(0)) { - sendEmptyMessage(0); - } - } - - void forceScan() { - removeMessages(0); - sendEmptyMessage(0); - } - - void pause() { - mRetry = 0; - removeMessages(0); - } - - @Override - public void handleMessage(Message message) { - if (mWifiSettings.mWifiManager.startScan()) { - mRetry = 0; - } else if (++mRetry >= 3) { - mRetry = 0; - Activity activity = mWifiSettings.getActivity(); - if (activity != null) { - Toast.makeText(activity, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show(); - } - return; - } - sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS); - } - } - public WifiSettings() { super(DISALLOW_CONFIG_WIFI); - mFilter = new IntentFilter(); - mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); - mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); - mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - handleEvent(intent); - } - }; - - mScanner = new Scanner(this); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + mWifiTracker = new WifiTracker(getActivity(), this, true, true); + mWifiManager = mWifiTracker.getManager(); mConnectListener = new WifiManager.ActionListener() { @Override @@ -318,14 +223,14 @@ public class WifiSettings extends RestrictedSettingsFragment if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) { String ssid = intent.getStringExtra(EXTRA_START_CONNECT_SSID); - updateAccessPoints(); + onAccessPointsChanged(); PreferenceScreen preferenceScreen = getPreferenceScreen(); for (int i = 0; i < preferenceScreen.getPreferenceCount(); i++) { Preference preference = preferenceScreen.getPreference(i); - if (preference instanceof AccessPoint) { - AccessPoint accessPoint = (AccessPoint) preference; - if (ssid.equals(accessPoint.ssid) && accessPoint.networkId == -1 - && accessPoint.security != AccessPoint.SECURITY_NONE) { + if (preference instanceof AccessPointPreference) { + AccessPoint accessPoint = ((AccessPointPreference) preference).getAccessPoint(); + if (ssid.equals(accessPoint.getSsid()) && !accessPoint.isSaved() + && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { onPreferenceTreeClick(preferenceScreen, preference); break; } @@ -367,8 +272,7 @@ public class WifiSettings extends RestrictedSettingsFragment mWifiEnabler.resume(activity); } - activity.registerReceiver(mReceiver, mFilter); - updateAccessPoints(); + mWifiTracker.startTracking(); } @Override @@ -378,8 +282,7 @@ public class WifiSettings extends RestrictedSettingsFragment mWifiEnabler.pause(); } - getActivity().unregisterReceiver(mReceiver); - mScanner.pause(); + mWifiTracker.stopTracking(); } @Override @@ -395,7 +298,7 @@ public class WifiSettings extends RestrictedSettingsFragment * @param menu */ void addOptionsMenuItems(Menu menu) { - final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); + final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled(); TypedArray ta = getActivity().getTheme().obtainStyledAttributes( new int[] {R.attr.ic_menu_add, R.attr.ic_wps}); menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) @@ -413,6 +316,8 @@ public class WifiSettings extends RestrictedSettingsFragment .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + showAppMenuItem = menu.add(Menu.NONE, MENU_ID_APPS, 0, R.string.wifi_menu_apps); + showAppMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); ta.recycle(); } @@ -458,12 +363,10 @@ public class WifiSettings extends RestrictedSettingsFragment showDialog(WPS_PIN_DIALOG_ID); return true; case MENU_ID_SCAN: - if (mWifiManager.isWifiEnabled()) { - mScanner.forceScan(); - } + mWifiTracker.forceScan(); return true; case MENU_ID_ADD_NETWORK: - if (mWifiManager.isWifiEnabled()) { + if (mWifiTracker.isWifiEnabled()) { onAddNetworkPressed(); } return true; @@ -489,6 +392,16 @@ public class WifiSettings extends RestrictedSettingsFragment null); } return true; + case MENU_ID_APPS: + showAppIcons = !showAppIcons; + + if (showAppIcons) { + showAppMenuItem.setTitle(R.string.wifi_menu_apps_strength); + } else { + showAppMenuItem.setTitle(R.string.wifi_menu_apps); + } + onAccessPointsChanged(); + return true; } return super.onOptionsItemSelected(item); } @@ -499,29 +412,24 @@ public class WifiSettings extends RestrictedSettingsFragment Preference preference = (Preference) getListView().getItemAtPosition( ((AdapterContextMenuInfo) info).position); - if (preference instanceof AccessPoint) { - mSelectedAccessPoint = (AccessPoint) preference; - menu.setHeaderTitle(mSelectedAccessPoint.ssid); - if (mSelectedAccessPoint.getLevel() != -1) { - if (mSelectedAccessPoint.getState() == null) { - menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); - } + if (preference instanceof AccessPointPreference) { + mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint(); + menu.setHeaderTitle(mSelectedAccessPoint.getSsid()); + if (mSelectedAccessPoint.isConnectable()) { + menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); } - if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER && - (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID || - (mSelectedAccessPoint.getNetworkInfo() != null && - mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED))) { - // Allow forgetting a network if the current user is the owner and either the - // network is saved or ephemerally connected. (In the latter case, "forget" - // blacklists the network so it won't be used again, ephemerally). + if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) { + // Allow forgetting a network if either the network is saved or ephemerally + // connected. (In the latter case, "forget" blacklists the network so it won't + // be used again, ephemerally). menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); } - if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { + if (mSelectedAccessPoint.isSaved()) { menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); if (nfcAdapter != null && nfcAdapter.isEnabled() && - mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) { + mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { // Only allow writing of NFC tags for password-protected networks. menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc); } @@ -537,9 +445,9 @@ public class WifiSettings extends RestrictedSettingsFragment } switch (item.getItemId()) { case MENU_ID_CONNECT: { - if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { - connect(mSelectedAccessPoint.networkId); - } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) { + if (mSelectedAccessPoint.isSaved()) { + connect(mSelectedAccessPoint.getConfig()); + } else if (mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { /** Bypass dialog for unsecured networks */ mSelectedAccessPoint.generateOpenNetworkConfig(); connect(mSelectedAccessPoint.getConfig()); @@ -566,12 +474,11 @@ public class WifiSettings extends RestrictedSettingsFragment @Override public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { - if (preference instanceof AccessPoint) { - mSelectedAccessPoint = (AccessPoint) preference; + if (preference instanceof AccessPointPreference) { + mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint(); /** Bypass dialog for unsecured, unsaved, and inactive networks */ - if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE && - mSelectedAccessPoint.networkId == INVALID_NETWORK_ID && - !mSelectedAccessPoint.isActive()) { + if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE && + !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { mSelectedAccessPoint.generateOpenNetworkConfig(); if (!savedNetworksExist) { savedNetworksExist = true; @@ -637,7 +544,8 @@ public class WifiSettings extends RestrictedSettingsFragment * Shows the latest access points available with supplemental information like * the strength of network and the security for it. */ - private void updateAccessPoints() { + @Override + public void onAccessPointsChanged() { // Safeguard from some delayed event handling if (getActivity() == null) return; @@ -647,15 +555,11 @@ public class WifiSettings extends RestrictedSettingsFragment } final int wifiState = mWifiManager.getWifiState(); - //when we update the screen, check if verbose logging has been turned on or off - mVerboseLogging = mWifiManager.getVerboseLoggingLevel(); - switch (wifiState) { case WifiManager.WIFI_STATE_ENABLED: // AccessPoints are automatically sorted with TreeSet. final Collection<AccessPoint> accessPoints = - constructAccessPoints(getActivity(), mWifiManager, mLastInfo, - mLastNetworkInfo); + mWifiTracker.getAccessPoints(); getPreferenceScreen().removeAll(); if (accessPoints.size() == 0) { addMessagePreference(R.string.wifi_empty_list_wifi_on); @@ -664,7 +568,14 @@ public class WifiSettings extends RestrictedSettingsFragment for (AccessPoint accessPoint : accessPoints) { // Ignore access points that are out of range. if (accessPoint.getLevel() != -1) { - getPreferenceScreen().addPreference(accessPoint); + AccessPointPreference preference = new AccessPointPreference(accessPoint, + getActivity()); + if (showAppIcons) { + preference.showAppIcon(); + } + + getPreferenceScreen().addPreference(preference); + accessPoint.setListener(this); } } break; @@ -681,6 +592,11 @@ public class WifiSettings extends RestrictedSettingsFragment setOffMessage(); break; } + // Update "Saved Networks" menu option. + if (savedNetworksExist != mWifiTracker.doSavedNetworksExist()) { + savedNetworksExist = !savedNetworksExist; + getActivity().invalidateOptionsMenu(); + } } protected TextView initEmptyView() { @@ -714,127 +630,14 @@ public class WifiSettings extends RestrictedSettingsFragment getPreferenceScreen().removeAll(); } - /** Returns sorted list of access points */ - private static List<AccessPoint> constructAccessPoints(Context context, - WifiManager wifiManager, WifiInfo lastInfo, NetworkInfo lastNetworkInfo) { - ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); - /** Lookup table to more quickly update AccessPoints by only considering objects with the - * correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */ - Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>(); - - final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks(); - if (configs != null) { - // Update "Saved Networks" menu option. - if (savedNetworksExist != (configs.size() > 0)) { - savedNetworksExist = !savedNetworksExist; - if (context instanceof Activity) { - ((Activity) context).invalidateOptionsMenu(); - } - } - for (WifiConfiguration config : configs) { - if (config.selfAdded && config.numAssociation == 0) { - continue; - } - AccessPoint accessPoint = new AccessPoint(context, config); - if (lastInfo != null && lastNetworkInfo != null) { - accessPoint.update(lastInfo, lastNetworkInfo); - } - accessPoints.add(accessPoint); - apMap.put(accessPoint.ssid, accessPoint); - } - } - - final List<ScanResult> results = wifiManager.getScanResults(); - if (results != null) { - for (ScanResult result : results) { - // Ignore hidden and ad-hoc networks. - if (result.SSID == null || result.SSID.length() == 0 || - result.capabilities.contains("[IBSS]")) { - continue; - } - - boolean found = false; - for (AccessPoint accessPoint : apMap.getAll(result.SSID)) { - if (accessPoint.update(result)) - found = true; - } - if (!found) { - AccessPoint accessPoint = new AccessPoint(context, result); - if (lastInfo != null && lastNetworkInfo != null) { - accessPoint.update(lastInfo, lastNetworkInfo); - } - accessPoints.add(accessPoint); - apMap.put(accessPoint.ssid, accessPoint); - } - } - } - - // Pre-sort accessPoints to speed preference insertion - Collections.sort(accessPoints); - return accessPoints; - } - - private void handleEvent(Intent intent) { - String action = intent.getAction(); - if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { - updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN)); - } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) || - WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) || - WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) { - updateAccessPoints(); - } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { - NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_INFO); - mConnected.set(info.isConnected()); - changeNextButtonState(info.isConnected()); - updateAccessPoints(); - updateNetworkInfo(info); - } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { - updateNetworkInfo(null); - } - } - - private void updateNetworkInfo(NetworkInfo networkInfo) { - /* sticky broadcasts can call this when wifi is disabled */ - if (!mWifiManager.isWifiEnabled()) { - mScanner.pause(); - return; - } - - if (networkInfo != null && - networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) { - mScanner.pause(); - } else { - mScanner.resume(); - } - - mLastInfo = mWifiManager.getConnectionInfo(); - if (networkInfo != null) { - mLastNetworkInfo = networkInfo; - } - - for (int i = getPreferenceScreen().getPreferenceCount() - 1; i >= 0; --i) { - // Maybe there's a WifiConfigPreference - Preference preference = getPreferenceScreen().getPreference(i); - if (preference instanceof AccessPoint) { - final AccessPoint accessPoint = (AccessPoint) preference; - accessPoint.update(mLastInfo, mLastNetworkInfo); - } - } - } - - private void updateWifiState(int state) { + @Override + public void onWifiStateChanged(int state) { Activity activity = getActivity(); if (activity != null) { activity.invalidateOptionsMenu(); } switch (state) { - case WifiManager.WIFI_STATE_ENABLED: - mScanner.resume(); - return; // not break, to avoid the call to pause() below - case WifiManager.WIFI_STATE_ENABLING: addMessagePreference(R.string.wifi_starting); break; @@ -843,10 +646,11 @@ public class WifiSettings extends RestrictedSettingsFragment setOffMessage(); break; } + } - mLastInfo = null; - mLastNetworkInfo = null; - mScanner.pause(); + @Override + public void onConnectedChanged() { + changeNextButtonState(mWifiTracker.isConnected()); } /** @@ -878,8 +682,8 @@ public class WifiSettings extends RestrictedSettingsFragment if (config == null) { if (mSelectedAccessPoint != null - && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { - connect(mSelectedAccessPoint.networkId); + && mSelectedAccessPoint.isSaved()) { + connect(mSelectedAccessPoint.getConfig()); } } else if (config.networkId != INVALID_NETWORK_ID) { if (mSelectedAccessPoint != null) { @@ -893,32 +697,25 @@ public class WifiSettings extends RestrictedSettingsFragment } } - if (mWifiManager.isWifiEnabled()) { - mScanner.resume(); - } - updateAccessPoints(); + mWifiTracker.resumeScanning(); } /* package */ void forget() { - if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) { + if (!mSelectedAccessPoint.isSaved()) { if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) { // Network is active but has no network ID - must be ephemeral. mWifiManager.disableEphemeralNetwork( - AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid)); + AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsid())); } else { // Should not happen, but a monkey seems to trigger it Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig()); return; } } else { - mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener); + mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener); } - - if (mWifiManager.isWifiEnabled()) { - mScanner.resume(); - } - updateAccessPoints(); + mWifiTracker.resumeScanning(); // We need to rename/replace "Next" button in wifi setup context. changeNextButtonState(false); @@ -936,9 +733,7 @@ public class WifiSettings extends RestrictedSettingsFragment * Refreshes acccess points and ask Wifi module to scan networks again. */ /* package */ void refreshAccessPoints() { - if (mWifiManager.isWifiEnabled()) { - mScanner.resume(); - } + mWifiTracker.resumeScanning(); getPreferenceScreen().removeAll(); } @@ -953,7 +748,7 @@ public class WifiSettings extends RestrictedSettingsFragment } /* package */ int getAccessPointsCount() { - final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); + final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled(); if (wifiIsEnabled) { return getPreferenceScreen().getPreferenceCount(); } else { @@ -965,18 +760,14 @@ public class WifiSettings extends RestrictedSettingsFragment * Requests wifi module to pause wifi scan. May be ignored when the module is disabled. */ /* package */ void pauseWifiScan() { - if (mWifiManager.isWifiEnabled()) { - mScanner.pause(); - } + mWifiTracker.pauseScanning(); } /** * Requests wifi module to resume wifi scan. May be ignored when the module is disabled. */ /* package */ void resumeWifiScan() { - if (mWifiManager.isWifiEnabled()) { - mScanner.resume(); - } + mWifiTracker.resumeScanning(); } @Override @@ -984,6 +775,16 @@ public class WifiSettings extends RestrictedSettingsFragment return R.string.help_url_wifi; } + @Override + public void onAccessPointChanged(AccessPoint accessPoint) { + ((AccessPointPreference) accessPoint.getTag()).refresh(); + } + + @Override + public void onLevelChanged(AccessPoint accessPoint) { + ((AccessPointPreference) accessPoint.getTag()).onLevelChanged(); + } + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override @@ -998,16 +799,12 @@ public class WifiSettings extends RestrictedSettingsFragment data.keywords = res.getString(R.string.keywords_wifi); result.add(data); - // Add available Wi-Fi access points - WifiManager wifiManager = - (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + // Add saved Wi-Fi access points final Collection<AccessPoint> accessPoints = - constructAccessPoints(context, wifiManager, null, null); + WifiTracker.getCurrentAccessPoints(context, true, false); for (AccessPoint accessPoint : accessPoints) { - // We are indexing only the saved Wi-Fi networks. - if (accessPoint.getConfig() == null) continue; data = new SearchIndexableRaw(context); - data.title = accessPoint.getTitle().toString(); + data.title = accessPoint.getSsid(); data.screenTitle = res.getString(R.string.wifi_settings); data.enabled = enabled; result.add(data); diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java index c4a5c96..efa56d7 100644 --- a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java +++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java @@ -17,19 +17,14 @@ package com.android.settings.wifi; import android.content.Intent; -import android.content.res.TypedArray; -import android.database.DataSetObserver; import android.net.wifi.WifiConfiguration; import android.os.Bundle; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; -import android.view.MenuItem; +import android.view.MenuInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.AbsListView.LayoutParams; -import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; @@ -37,9 +32,9 @@ import com.android.settings.R; /** * This customized version of WifiSettings is shown to the user only during Setup Wizard. Menu - * selections are limited, clicking on an access point will auto-advance to the next screen (once - * connected), and, if the user opts to skip ahead without a wifi connection, a warning message - * alerts of possible carrier data charges or missing software updates. + * is not shown, clicking on an access point will auto-advance to the next screen (once connected), + * and, if the user opts to skip ahead without a wifi connection, a warning message alerts of + * possible carrier data charges or missing software updates. */ public class WifiSettingsForSetupWizard extends WifiSettings { @@ -49,7 +44,6 @@ public class WifiSettingsForSetupWizard extends WifiSettings { protected static final String EXTRA_SHOW_WIFI_REQUIRED_INFO = "wifi_show_wifi_required_info"; private View mAddOtherNetworkItem; - private ListAdapter mAdapter; private TextView mEmptyFooter; private boolean mListLastEmpty = false; @@ -98,15 +92,12 @@ public class WifiSettingsForSetupWizard extends WifiSettings { if (hasNextButton()) { getNextButton().setVisibility(View.GONE); } + } - mAdapter = getPreferenceScreen().getRootAdapter(); - mAdapter.registerDataSetObserver(new DataSetObserver() { - @Override - public void onChanged() { - super.onChanged(); - updateFooter(); - } - }); + @Override + public void onAccessPointsChanged() { + super.onAccessPointsChanged(); + updateFooter(getPreferenceScreen().getPreferenceCount() == 0); } @Override @@ -121,18 +112,8 @@ public class WifiSettingsForSetupWizard extends WifiSettings { } @Override - /* package */ void addOptionsMenuItems(Menu menu) { - final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); - final TypedArray ta = getActivity().getTheme() - .obtainStyledAttributes(new int[] {R.attr.ic_wps}); - menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc) - .setIcon(ta.getDrawable(0)) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - ta.recycle(); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // Do not show menu during setup wizard } @Override @@ -151,17 +132,12 @@ public class WifiSettingsForSetupWizard extends WifiSettings { @Override protected TextView initEmptyView() { - mEmptyFooter = new TextView(getActivity()); - mEmptyFooter.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - mEmptyFooter.setGravity(Gravity.CENTER); - mEmptyFooter.setCompoundDrawablesWithIntrinsicBounds(0, - R.drawable.ic_wifi_emptystate, 0,0); + final LayoutInflater inflater = LayoutInflater.from(getActivity()); + mEmptyFooter = (TextView) inflater.inflate(R.layout.setup_wifi_empty, getListView(), false); return mEmptyFooter; } - protected void updateFooter() { - final boolean isEmpty = mAdapter.isEmpty(); + protected void updateFooter(boolean isEmpty) { if (isEmpty != mListLastEmpty) { final ListView list = getListView(); if (isEmpty) { diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java deleted file mode 100644 index 2588309..0000000 --- a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Copyright (C) 2010 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 com.android.settings.wifi; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.preference.PreferenceScreen; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.Window; -import android.view.inputmethod.InputMethodManager; -import android.widget.Button; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.android.settings.R; - -import java.util.Collection; -import java.util.EnumMap; -import java.util.List; - -/** - * WifiSetings Activity specific for SetupWizard with X-Large screen size. - */ -public class WifiSettingsForSetupWizardXL extends Activity implements OnClickListener { - private static final String TAG = "SetupWizard"; - private static final boolean DEBUG = true; - - // lock orientation into landscape or portrait - private static final String EXTRA_PREFS_LANDSCAPE_LOCK = "extra_prefs_landscape_lock"; - private static final String EXTRA_PREFS_PORTRAIT_LOCK = "extra_prefs_portrait_lock"; - - private static final EnumMap<DetailedState, DetailedState> sNetworkStateMap = - new EnumMap<DetailedState, DetailedState>(DetailedState.class); - - static { - sNetworkStateMap.put(DetailedState.IDLE, DetailedState.DISCONNECTED); - sNetworkStateMap.put(DetailedState.SCANNING, DetailedState.SCANNING); - sNetworkStateMap.put(DetailedState.CONNECTING, DetailedState.CONNECTING); - sNetworkStateMap.put(DetailedState.AUTHENTICATING, DetailedState.CONNECTING); - sNetworkStateMap.put(DetailedState.OBTAINING_IPADDR, DetailedState.CONNECTING); - sNetworkStateMap.put(DetailedState.CONNECTED, DetailedState.CONNECTED); - sNetworkStateMap.put(DetailedState.SUSPENDED, DetailedState.SUSPENDED); // ? - sNetworkStateMap.put(DetailedState.DISCONNECTING, DetailedState.DISCONNECTED); - sNetworkStateMap.put(DetailedState.DISCONNECTED, DetailedState.DISCONNECTED); - sNetworkStateMap.put(DetailedState.FAILED, DetailedState.FAILED); - } - - private WifiSettings mWifiSettings; - private WifiManager mWifiManager; - - /** Used for resizing a padding above title. Hiden when software keyboard is shown. */ - private View mTopPadding; - - /** Used for resizing a padding of main content. Hiden when software keyboard is shown. */ - private View mContentPadding; - - private TextView mTitleView; - /** - * The name of a network currently connecting, or trying to connect. - * This may be empty ("") at first, and updated when configuration is changed. - */ - private CharSequence mNetworkName = ""; - private CharSequence mEditingTitle; - - private ProgressBar mProgressBar; - private View mTopDividerNoProgress; - /** - * Used for resizing a padding between WifiSettings preference and bottom bar when - * ProgressBar is visible as a top divider. - */ - private View mBottomPadding; - - private Button mAddNetworkButton; - private Button mRefreshButton; - private Button mSkipOrNextButton; - private Button mBackButton; - - private Button mConnectButton; - - /** - * View enclosing {@link WifiSettings}. - */ - private View mWifiSettingsFragmentLayout; - private View mConnectingStatusLayout; - private TextView mConnectingStatusView; - - /* - * States of current screen, which should be saved and restored when Activity is relaunched - * with orientation change, etc. - */ - private static final int SCREEN_STATE_DISCONNECTED = 0; - private static final int SCREEN_STATE_EDITING = 1; - private static final int SCREEN_STATE_CONNECTING = 2; - private static final int SCREEN_STATE_CONNECTED = 3; - - /** Current screen state. */ - private int mScreenState = SCREEN_STATE_DISCONNECTED; - - private WifiConfigUiForSetupWizardXL mWifiConfig; - - private InputMethodManager mInputMethodManager; - - /** - * Previous network connection state reported by main Wifi module. - * - * Note that we don't use original {@link DetailedState} object but simplified one translated - * using sNetworkStateMap. - */ - private DetailedState mPreviousNetworkState = DetailedState.DISCONNECTED; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.wifi_settings_for_setup_wizard_xl); - - mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE); - // There's no button here enabling wifi network, so we need to enable it without - // users' request. - mWifiManager.setWifiEnabled(true); - - mWifiSettings = - (WifiSettings)getFragmentManager().findFragmentById(R.id.wifi_setup_fragment); - mInputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); - - initViews(); - - // At first, Wifi module doesn't return SCANNING state (it's too early), so we manually - // show it. - showScanningState(); - } - - private void initViews() { - Intent intent = getIntent(); - - if (intent.getBooleanExtra("firstRun", false)) { - final View layoutRoot = findViewById(R.id.layout_root); - layoutRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_BACK); - } - if (intent.getBooleanExtra(EXTRA_PREFS_LANDSCAPE_LOCK, false)) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); - } - if (intent.getBooleanExtra(EXTRA_PREFS_PORTRAIT_LOCK, false)) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); - } - - mTitleView = (TextView)findViewById(R.id.wifi_setup_title); - mProgressBar = (ProgressBar)findViewById(R.id.scanning_progress_bar); - mProgressBar.setMax(2); - mTopDividerNoProgress = findViewById(R.id.top_divider_no_progress); - mBottomPadding = findViewById(R.id.bottom_padding); - - mProgressBar.setVisibility(View.VISIBLE); - mProgressBar.setIndeterminate(true); - mTopDividerNoProgress.setVisibility(View.GONE); - - mAddNetworkButton = (Button)findViewById(R.id.wifi_setup_add_network); - mAddNetworkButton.setOnClickListener(this); - mRefreshButton = (Button)findViewById(R.id.wifi_setup_refresh_list); - mRefreshButton.setOnClickListener(this); - mSkipOrNextButton = (Button)findViewById(R.id.wifi_setup_skip_or_next); - mSkipOrNextButton.setOnClickListener(this); - mConnectButton = (Button)findViewById(R.id.wifi_setup_connect); - mConnectButton.setOnClickListener(this); - mBackButton = (Button)findViewById(R.id.wifi_setup_cancel); - mBackButton.setOnClickListener(this); - - mTopPadding = findViewById(R.id.top_padding); - mContentPadding = findViewById(R.id.content_padding); - - mWifiSettingsFragmentLayout = findViewById(R.id.wifi_settings_fragment_layout); - mConnectingStatusLayout = findViewById(R.id.connecting_status_layout); - mConnectingStatusView = (TextView) findViewById(R.id.connecting_status); - } - - private void restoreFirstVisibilityState() { - showDefaultTitle(); - mAddNetworkButton.setVisibility(View.VISIBLE); - mRefreshButton.setVisibility(View.VISIBLE); - mSkipOrNextButton.setVisibility(View.VISIBLE); - mConnectButton.setVisibility(View.GONE); - mBackButton.setVisibility(View.GONE); - setPaddingVisibility(View.VISIBLE); - } - - @Override - public void onClick(View view) { - hideSoftwareKeyboard(); - if (view == mAddNetworkButton) { - if (DEBUG) Log.d(TAG, "AddNetwork button pressed"); - onAddNetworkButtonPressed(); - } else if (view == mRefreshButton) { - if (DEBUG) Log.d(TAG, "Refresh button pressed"); - refreshAccessPoints(true); - } else if (view == mSkipOrNextButton) { - if (DEBUG) Log.d(TAG, "Skip/Next button pressed"); - if (TextUtils.equals(getString(R.string.wifi_setup_skip), ((Button)view).getText())) { - // We don't want to let Wifi enabled when a user press skip without choosing - // any access point. - mWifiManager.setWifiEnabled(false); - // Notify "skip" - setResult(RESULT_FIRST_USER); - } else { - setResult(RESULT_OK); - } - finish(); - } else if (view == mConnectButton) { - if (DEBUG) Log.d(TAG, "Connect button pressed"); - onConnectButtonPressed(); - } else if (view == mBackButton) { - if (DEBUG) Log.d(TAG, "Back button pressed"); - onBackButtonPressed(); - } - } - - private void hideSoftwareKeyboard() { - if (DEBUG) Log.i(TAG, "Hiding software keyboard."); - final View focusedView = getCurrentFocus(); - if (focusedView != null) { - mInputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); - } - } - - // Called from WifiSettings - /* package */ void updateConnectionState(DetailedState originalState) { - final DetailedState state = sNetworkStateMap.get(originalState); - - if (originalState == DetailedState.FAILED) { - // We clean up the current connectivity status and let users select another network - // if they want. - refreshAccessPoints(true); - } - - switch (state) { - case SCANNING: { - if (mScreenState == SCREEN_STATE_DISCONNECTED) { - if (mWifiSettings.getAccessPointsCount() == 0) { - showScanningState(); - } else { - showDisconnectedProgressBar(); - mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); - mBottomPadding.setVisibility(View.GONE); - } - } else { - showDisconnectedProgressBar(); - } - break; - } - case CONNECTING: { - if (mScreenState == SCREEN_STATE_CONNECTING) { - showConnectingState(); - } - break; - } - case CONNECTED: { - showConnectedState(); - break; - } - default: // DISCONNECTED, FAILED - if (mScreenState != SCREEN_STATE_CONNECTED && - mWifiSettings.getAccessPointsCount() > 0) { - showDisconnectedState(Summary.get(this, state, false /* isEphemeral */)); - } - break; - } - mPreviousNetworkState = state; - } - - private void showDisconnectedState(String stateString) { - showDisconnectedProgressBar(); - if (mScreenState == SCREEN_STATE_DISCONNECTED && - mWifiSettings.getAccessPointsCount() > 0) { - mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); - mBottomPadding.setVisibility(View.GONE); - } - mAddNetworkButton.setEnabled(true); - mRefreshButton.setEnabled(true); - } - - private void showConnectingState() { - mScreenState = SCREEN_STATE_CONNECTING; - - mBackButton.setVisibility(View.VISIBLE); - // We save this title and show it when authentication failed. - mEditingTitle = mTitleView.getText(); - showConnectingTitle(); - showConnectingProgressBar(); - - setPaddingVisibility(View.VISIBLE); - } - - private void showConnectedState() { - // Once we show "connected" screen, we won't change it even when the device becomes - // disconnected afterwards. We keep the state unless a user explicitly cancel it - // (by pressing "back" button). - mScreenState = SCREEN_STATE_CONNECTED; - - hideSoftwareKeyboard(); - setPaddingVisibility(View.VISIBLE); - - showConnectedTitle(); - showConnectedProgressBar(); - - mWifiSettingsFragmentLayout.setVisibility(View.GONE); - mConnectingStatusLayout.setVisibility(View.VISIBLE); - - mConnectingStatusView.setText(R.string.wifi_setup_description_connected); - mConnectButton.setVisibility(View.GONE); - mAddNetworkButton.setVisibility(View.GONE); - mRefreshButton.setVisibility(View.GONE); - mBackButton.setVisibility(View.VISIBLE); - mBackButton.setText(R.string.wifi_setup_back); - mSkipOrNextButton.setVisibility(View.VISIBLE); - mSkipOrNextButton.setEnabled(true); - } - - private void showDefaultTitle() { - mTitleView.setText(getString(R.string.wifi_setup_title)); - } - - private void showAddNetworkTitle() { - mNetworkName = ""; - mTitleView.setText(R.string.wifi_setup_title_add_network); - } - - private void showEditingTitle() { - if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { - if (mWifiConfig.getController() != null && - mWifiConfig.getController().getConfig() != null) { - mNetworkName = mWifiConfig.getController().getConfig().SSID; - } else { - Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + - "Ignore them."); - } - } - mTitleView.setText(getString(R.string.wifi_setup_title_editing_network, mNetworkName)); - } - - private void showConnectingTitle() { - if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { - if (mWifiConfig.getController() != null && - mWifiConfig.getController().getConfig() != null) { - mNetworkName = mWifiConfig.getController().getConfig().SSID; - } else { - Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + - "Ignore them."); - } - } - mTitleView.setText(getString(R.string.wifi_setup_title_connecting_network, mNetworkName)); - } - - private void showConnectedTitle() { - if (TextUtils.isEmpty(mNetworkName) && mWifiConfig != null) { - if (mWifiConfig.getController() != null && - mWifiConfig.getController().getConfig() != null) { - mNetworkName = mWifiConfig.getController().getConfig().SSID; - } else { - Log.w(TAG, "Unexpected null found (WifiController or WifiConfig is null). " + - "Ignore them."); - } - } - mTitleView.setText(getString(R.string.wifi_setup_title_connected_network, mNetworkName)); - } - - /** - * Shows top divider with ProgressBar without defining the state of the ProgressBar. - * - * @see #showScanningProgressBar() - * @see #showConnectedProgressBar() - * @see #showConnectingProgressBar() - */ - private void showTopDividerWithProgressBar() { - mProgressBar.setVisibility(View.VISIBLE); - mTopDividerNoProgress.setVisibility(View.GONE); - mBottomPadding.setVisibility(View.GONE); - } - - private void showScanningState() { - setPaddingVisibility(View.VISIBLE); - mWifiSettingsFragmentLayout.setVisibility(View.GONE); - showScanningProgressBar(); - } - - private void onAddNetworkButtonPressed() { - mWifiSettings.onAddNetworkPressed(); - } - - /** - * Called when the screen enters wifi configuration UI. UI widget for configuring network - * (a.k.a. ConfigPreference) should be taken care of by caller side. - * This method should handle buttons' visibility/enabled. - * @param selectedAccessPoint AccessPoint object being selected. null when a user pressed - * "Add network" button, meaning there's no selected access point. - */ - /* package */ void showConfigUi(AccessPoint selectedAccessPoint, boolean edit) { - mScreenState = SCREEN_STATE_EDITING; - - if (selectedAccessPoint != null && - (selectedAccessPoint.security == AccessPoint.SECURITY_WEP || - selectedAccessPoint.security == AccessPoint.SECURITY_PSK)) { - // We forcibly set edit as true so that users can modify every field if they want, - // while config UI doesn't allow them to edit some of them when edit is false - // (e.g. password field is hiden when edit==false). - edit = true; - } - - // We don't want to keep scanning Wifi networks during users' configuring a network. - mWifiSettings.pauseWifiScan(); - - mWifiSettingsFragmentLayout.setVisibility(View.GONE); - mConnectingStatusLayout.setVisibility(View.GONE); - final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); - parent.setVisibility(View.VISIBLE); - parent.removeAllViews(); - mWifiConfig = new WifiConfigUiForSetupWizardXL(this, parent, selectedAccessPoint, edit); - - if (selectedAccessPoint == null) { // "Add network" flow - showAddNetworkTitle(); - mConnectButton.setVisibility(View.VISIBLE); - - showDisconnectedProgressBar(); - showEditingButtonState(); - } else if (selectedAccessPoint.security == AccessPoint.SECURITY_NONE) { - mNetworkName = selectedAccessPoint.getTitle().toString(); - - // onConnectButtonPressed() will change visibility status. - mConnectButton.performClick(); - } else { - mNetworkName = selectedAccessPoint.getTitle().toString(); - showEditingTitle(); - showDisconnectedProgressBar(); - showEditingButtonState(); - if (selectedAccessPoint.security == AccessPoint.SECURITY_EAP) { - onEapNetworkSelected(); - } else { - mConnectButton.setVisibility(View.VISIBLE); - - // WifiConfigController shows Connect button as "Save" when edit==true and a user - // tried to connect the network. - // In SetupWizard, we just show the button as "Connect" instead. - mConnectButton.setText(R.string.wifi_connect); - mBackButton.setText(R.string.wifi_setup_cancel); - } - } - } - - /** - * Called before security fields are correctly set by {@link WifiConfigController}. - * - * @param view security field view - * @param accessPointSecurity type of security. e.g. AccessPoint.SECURITY_NONE - * @return true when it is ok for the caller to init security fields. false when - * all security fields are managed by this method, and thus the caller shouldn't touch them. - */ - /* package */ boolean initSecurityFields(View view, int accessPointSecurity) { - // Reset all states tweaked below. - view.findViewById(R.id.eap_not_supported).setVisibility(View.GONE); - view.findViewById(R.id.eap_not_supported_for_add_network).setVisibility(View.GONE); - view.findViewById(R.id.ssid_text).setVisibility(View.VISIBLE); - view.findViewById(R.id.ssid_layout).setVisibility(View.VISIBLE); - - if (accessPointSecurity == AccessPoint.SECURITY_EAP) { - setPaddingVisibility(View.VISIBLE); - hideSoftwareKeyboard(); - - // In SetupWizard for XLarge screen, we don't have enough space for showing - // configurations needed for EAP. We instead disable the whole feature there and let - // users configure those networks after the setup. - if (view.findViewById(R.id.type_ssid).getVisibility() == View.VISIBLE) { - view.findViewById(R.id.eap_not_supported_for_add_network) - .setVisibility(View.VISIBLE); - } else { - view.findViewById(R.id.eap_not_supported).setVisibility(View.VISIBLE); - } - view.findViewById(R.id.security_fields).setVisibility(View.GONE); - view.findViewById(R.id.ssid_text).setVisibility(View.GONE); - view.findViewById(R.id.ssid_layout).setVisibility(View.GONE); - onEapNetworkSelected(); - - // This method did init security fields by itself. The caller must not do it. - return false; - } - - mConnectButton.setVisibility(View.VISIBLE); - setPaddingVisibility(View.GONE); - - // In "add network" flow, we'll see multiple initSecurityFields() calls with different - // accessPointSecurity variable. We want to show software keyboard conditionally everytime - // when this method is called. - if (mWifiConfig != null) { - if (accessPointSecurity == AccessPoint.SECURITY_PSK || - accessPointSecurity == AccessPoint.SECURITY_WEP) { - mWifiConfig.requestFocusAndShowKeyboard(R.id.password); - } else { - mWifiConfig.requestFocusAndShowKeyboard(R.id.ssid); - } - } - - // Let the caller init security fields. - return true; - } - - private void onEapNetworkSelected() { - mConnectButton.setVisibility(View.GONE); - mBackButton.setText(R.string.wifi_setup_back); - } - - private void showEditingButtonState() { - mSkipOrNextButton.setVisibility(View.GONE); - mAddNetworkButton.setVisibility(View.GONE); - mRefreshButton.setVisibility(View.GONE); - mBackButton.setVisibility(View.VISIBLE); - } - - // May be called when user press "connect" button in WifiDialog - /* package */ void onConnectButtonPressed() { - mScreenState = SCREEN_STATE_CONNECTING; - - mWifiSettings.submit(mWifiConfig.getController()); - - // updateConnectionState() isn't called soon by the main Wifi module after the user's - // "connect" request, and the user still sees "not connected" message for a while, which - // looks strange for users though legitimate from the view of the module. - // - // We instead manually show "connecting" message before the system gets actual - // "connecting" message from Wifi module. - showConnectingState(); - - // Might be better to delay showing this button. - mBackButton.setVisibility(View.VISIBLE); - mBackButton.setText(R.string.wifi_setup_back); - - final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); - parent.setVisibility(View.GONE); - mConnectingStatusLayout.setVisibility(View.VISIBLE); - mConnectingStatusView.setText(R.string.wifi_setup_description_connecting); - - mSkipOrNextButton.setVisibility(View.VISIBLE); - mSkipOrNextButton.setEnabled(false); - mConnectButton.setVisibility(View.GONE); - mAddNetworkButton.setVisibility(View.GONE); - mRefreshButton.setVisibility(View.GONE); - } - - private void onBackButtonPressed() { - - if (mScreenState == SCREEN_STATE_CONNECTING || mScreenState == SCREEN_STATE_CONNECTED) { - if (DEBUG) Log.d(TAG, "Back button pressed after connect action."); - mScreenState = SCREEN_STATE_DISCONNECTED; - - // When a user press "Back" button after pressing "Connect" button, we want to cancel - // the "Connect" request and refresh the whole Wifi status. - restoreFirstVisibilityState(); - - mSkipOrNextButton.setEnabled(true); - changeNextButtonState(false); // Skip - - // Wifi list becomes empty for a moment. We show "scanning" effect to a user so that - // he/she won't be astonished there. This stops once the scan finishes. - showScanningState(); - - // Remembered networks may be re-used during SetupWizard, which confuse users. - // We force the module to forget them to reduce UX complexity - final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); - for (WifiConfiguration config : configs) { - if (DEBUG) { - Log.d(TAG, String.format("forgeting Wi-Fi network \"%s\" (id: %d)", - config.SSID, config.networkId)); - } - mWifiManager.forget(config.networkId, new WifiManager.ActionListener() { - public void onSuccess() { - } - public void onFailure(int reason) { - //TODO: Add failure UI - } - }); - } - - mWifiSettingsFragmentLayout.setVisibility(View.GONE); - refreshAccessPoints(true); - } else { // During user's Wifi configuration. - mScreenState = SCREEN_STATE_DISCONNECTED; - mWifiSettings.resumeWifiScan(); - - restoreFirstVisibilityState(); - - mAddNetworkButton.setEnabled(true); - mRefreshButton.setEnabled(true); - mSkipOrNextButton.setEnabled(true); - showDisconnectedProgressBar(); - mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); - mBottomPadding.setVisibility(View.GONE); - } - - setPaddingVisibility(View.VISIBLE); - mConnectingStatusLayout.setVisibility(View.GONE); - final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); - parent.removeAllViews(); - parent.setVisibility(View.GONE); - mWifiConfig = null; - } - - /** - * @param connected true when the device is connected to a specific network. - */ - /* package */ void changeNextButtonState(boolean connected) { - if (connected) { - mSkipOrNextButton.setText(R.string.wifi_setup_next); - } else { - mSkipOrNextButton.setText(R.string.wifi_setup_skip); - } - } - - /** - * Called when the list of AccessPoints are modified and this Activity needs to refresh - * the list. - * @param preferenceScreen - */ - /* package */ void onAccessPointsUpdated( - PreferenceScreen preferenceScreen, Collection<AccessPoint> accessPoints) { - // If we already show some of access points but the bar still shows "scanning" state, it - // should be stopped. - if (mProgressBar.isIndeterminate() && accessPoints.size() > 0) { - showDisconnectedProgressBar(); - if (mScreenState == SCREEN_STATE_DISCONNECTED) { - mWifiSettingsFragmentLayout.setVisibility(View.VISIBLE); - mBottomPadding.setVisibility(View.GONE); - } - mAddNetworkButton.setEnabled(true); - mRefreshButton.setEnabled(true); - } - - for (AccessPoint accessPoint : accessPoints) { - accessPoint.setLayoutResource(R.layout.custom_preference); - preferenceScreen.addPreference(accessPoint); - } - } - - private void refreshAccessPoints(boolean disconnectNetwork) { - showScanningState(); - - if (disconnectNetwork) { - mWifiManager.disconnect(); - } - - mWifiSettings.refreshAccessPoints(); - } - - /** - * Called when {@link WifiSettings} received - * {@link WifiManager#SUPPLICANT_STATE_CHANGED_ACTION}. - */ - /* package */ void onSupplicantStateChanged(Intent intent) { - final int errorCode = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1); - if (errorCode == WifiManager.ERROR_AUTHENTICATING) { - Log.i(TAG, "Received authentication error event."); - onAuthenticationFailure(); - } - } - - /** - * Called once when Authentication failed. - */ - private void onAuthenticationFailure() { - mScreenState = SCREEN_STATE_EDITING; - - mSkipOrNextButton.setVisibility(View.GONE); - mConnectButton.setVisibility(View.VISIBLE); - mConnectButton.setEnabled(true); - - if (!TextUtils.isEmpty(mEditingTitle)) { - mTitleView.setText(mEditingTitle); - } else { - Log.w(TAG, "Title during editing/adding a network was empty."); - showEditingTitle(); - } - - final ViewGroup parent = (ViewGroup)findViewById(R.id.wifi_config_ui); - parent.setVisibility(View.VISIBLE); - mConnectingStatusLayout.setVisibility(View.GONE); - - showDisconnectedProgressBar(); - setPaddingVisibility(View.GONE); - } - - // Used by WifiConfigUiForSetupWizardXL - /* package */ void setPaddingVisibility(int visibility) { - mTopPadding.setVisibility(visibility); - mContentPadding.setVisibility(visibility); - } - - private void showDisconnectedProgressBar() { - // The device may report DISCONNECTED during connecting to a network, at which we don't - // want to lose bottom padding of top divider implicitly added by ProgressBar. - if (mScreenState == SCREEN_STATE_DISCONNECTED) { - mProgressBar.setVisibility(View.GONE); - mProgressBar.setIndeterminate(false); - mTopDividerNoProgress.setVisibility(View.VISIBLE); - } else { - mProgressBar.setVisibility(View.VISIBLE); - mProgressBar.setIndeterminate(false); - mProgressBar.setProgress(0); - mTopDividerNoProgress.setVisibility(View.GONE); - } - } - - /** - * Shows top divider with ProgressBar, whose state is intermediate. - */ - private void showScanningProgressBar() { - showTopDividerWithProgressBar(); - mProgressBar.setIndeterminate(true); - } - - /** - * Shows top divider with ProgressBar, showing "connecting" state. - */ - private void showConnectingProgressBar() { - showTopDividerWithProgressBar(); - mProgressBar.setIndeterminate(false); - mProgressBar.setProgress(1); - } - - private void showConnectedProgressBar() { - showTopDividerWithProgressBar(); - mProgressBar.setIndeterminate(false); - mProgressBar.setProgress(2); - } - - /** - * Called when WifiManager is requested to save a network. - */ - /* package */ void onSaveNetwork(WifiConfiguration config) { - // We want to both save and connect a network. connectNetwork() does both. - mWifiManager.connect(config, new WifiManager.ActionListener() { - public void onSuccess() { - } - public void onFailure(int reason) { - //TODO: Add failure UI - } - }); - } -} diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java index 48921d7..85afb7c 100644 --- a/src/com/android/settings/wifi/WifiStatusTest.java +++ b/src/com/android/settings/wifi/WifiStatusTest.java @@ -17,6 +17,7 @@ package com.android.settings.wifi; import com.android.settings.R; +import com.android.settingslib.wifi.AccessPoint; import android.net.wifi.ScanResult; import java.net.HttpURLConnection; @@ -297,7 +298,8 @@ public class WifiStatusTest extends Activity { private void handleNetworkStateChanged(NetworkInfo networkInfo) { if (mWifiManager.isWifiEnabled()) { WifiInfo info = mWifiManager.getConnectionInfo(); - String summary = Summary.get(this, info.getSSID(), networkInfo.getDetailedState(), + String summary = AccessPoint.getSummary(this, info.getSSID(), + networkInfo.getDetailedState(), info.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID); mNetworkState.setText(summary); } diff --git a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java index 2667e0b..87850e5 100644 --- a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java +++ b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java @@ -45,6 +45,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.android.settings.R; +import com.android.settingslib.wifi.AccessPoint; import java.io.IOException; @@ -121,7 +122,7 @@ class WriteWifiConfigToNfcDialog extends AlertDialog String password = mPasswordView.getText().toString(); String wpsNfcConfigurationToken - = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId); + = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.getConfig().networkId); String passwordHex = byteArrayToHexString(password.getBytes()); String passwordLength = password.length() >= HEX_RADIX @@ -224,9 +225,9 @@ class WriteWifiConfigToNfcDialog extends AlertDialog private void enableSubmitIfAppropriate() { if (mPasswordView != null) { - if (mAccessPoint.security == AccessPoint.SECURITY_WEP) { + if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_WEP) { mSubmitButton.setEnabled(mPasswordView.length() > 0); - } else if (mAccessPoint.security == AccessPoint.SECURITY_PSK) { + } else if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_PSK) { mSubmitButton.setEnabled(mPasswordView.length() >= 8); } } else { |