summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/settings/AirplaneModeEnabler.java10
-rw-r--r--src/com/android/settings/AppHeader.java58
-rw-r--r--src/com/android/settings/ChooseLockGeneric.java184
-rw-r--r--src/com/android/settings/ChooseLockPassword.java17
-rw-r--r--src/com/android/settings/ChooseLockPattern.java9
-rw-r--r--src/com/android/settings/ChooseLockSettingsHelper.java2
-rw-r--r--src/com/android/settings/ConfirmLockPattern.java2
-rw-r--r--src/com/android/settings/CreateShortcut.java3
-rw-r--r--src/com/android/settings/CredentialStorage.java8
-rw-r--r--src/com/android/settings/CryptKeeper.java20
-rw-r--r--src/com/android/settings/DataUsageSummary.java12
-rw-r--r--src/com/android/settings/DevelopmentSettings.java137
-rw-r--r--src/com/android/settings/DeviceAdminAdd.java55
-rw-r--r--src/com/android/settings/DeviceAdminSettings.java11
-rw-r--r--src/com/android/settings/DisplaySettings.java20
-rw-r--r--src/com/android/settings/FingerprintEnroll.java472
-rw-r--r--src/com/android/settings/FingerprintSettings.java235
-rw-r--r--src/com/android/settings/HotspotOffReceiver.java4
-rw-r--r--src/com/android/settings/MasterClear.java11
-rw-r--r--src/com/android/settings/RadioInfo.java23
-rw-r--r--src/com/android/settings/SecuritySettings.java176
-rw-r--r--src/com/android/settings/Settings.java1
-rw-r--r--src/com/android/settings/SettingsActivity.java11
-rw-r--r--src/com/android/settings/SetupChooseLockGeneric.java24
-rw-r--r--src/com/android/settings/SetupChooseLockPassword.java4
-rw-r--r--src/com/android/settings/SetupChooseLockPattern.java4
-rw-r--r--src/com/android/settings/SetupRedactionInterstitial.java1
-rw-r--r--src/com/android/settings/TetherService.java51
-rw-r--r--src/com/android/settings/TetherSettings.java80
-rw-r--r--src/com/android/settings/TrustedCredentialsSettings.java11
-rw-r--r--src/com/android/settings/UsageAccessSettings.java332
-rw-r--r--src/com/android/settings/UserSpinnerAdapter.java19
-rw-r--r--src/com/android/settings/Utils.java85
-rw-r--r--src/com/android/settings/WirelessSettings.java10
-rw-r--r--src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java26
-rw-r--r--src/com/android/settings/accounts/AccountSettings.java3
-rw-r--r--src/com/android/settings/accounts/AccountSyncSettings.java9
-rw-r--r--src/com/android/settings/applications/AppInfoBase.java203
-rw-r--r--src/com/android/settings/applications/AppInfoWithHeader.java40
-rw-r--r--src/com/android/settings/applications/AppLaunchSettings.java191
-rw-r--r--src/com/android/settings/applications/AppPermissionSettings.java222
-rw-r--r--src/com/android/settings/applications/AppStorageSettings.java501
-rw-r--r--src/com/android/settings/applications/HeaderPreference.java61
-rwxr-xr-xsrc/com/android/settings/applications/InstalledAppDetails.java1258
-rw-r--r--src/com/android/settings/applications/ProcStatsEntry.java330
-rw-r--r--src/com/android/settings/applications/ProcStatsPackageEntry.java145
-rw-r--r--src/com/android/settings/applications/ProcessStatsDetail.java231
-rw-r--r--src/com/android/settings/applications/ProcessStatsPreference.java11
-rw-r--r--src/com/android/settings/applications/ProcessStatsUi.java253
-rw-r--r--src/com/android/settings/applications/RunningState.java78
-rwxr-xr-xsrc/com/android/settings/bluetooth/A2dpProfile.java214
-rw-r--r--src/com/android/settings/bluetooth/BluetoothCallback.java29
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDeviceFilter.java169
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDevicePreference.java61
-rwxr-xr-xsrc/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java7
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDiscoverableTimeoutReceiver.java87
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java2
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEnabler.java9
-rwxr-xr-xsrc/com/android/settings/bluetooth/BluetoothEventManager.java390
-rw-r--r--src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java4
-rwxr-xr-xsrc/com/android/settings/bluetooth/BluetoothPairingDialog.java5
-rwxr-xr-xsrc/com/android/settings/bluetooth/BluetoothPermissionActivity.java6
-rw-r--r--src/com/android/settings/bluetooth/BluetoothPermissionRequest.java5
-rwxr-xr-xsrc/com/android/settings/bluetooth/BluetoothSettings.java10
-rw-r--r--src/com/android/settings/bluetooth/BluetoothVisibilityTimeoutFragment.java68
-rwxr-xr-xsrc/com/android/settings/bluetooth/CachedBluetoothDevice.java787
-rwxr-xr-xsrc/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java172
-rw-r--r--src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java15
-rw-r--r--src/com/android/settings/bluetooth/DevicePickerFragment.java2
-rwxr-xr-xsrc/com/android/settings/bluetooth/DeviceProfilesSettings.java9
-rw-r--r--src/com/android/settings/bluetooth/DockService.java69
-rwxr-xr-xsrc/com/android/settings/bluetooth/HeadsetProfile.java227
-rwxr-xr-xsrc/com/android/settings/bluetooth/HidProfile.java201
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothAdapter.java216
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothManager.java123
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothPreferences.java5
-rwxr-xr-xsrc/com/android/settings/bluetooth/LocalBluetoothProfile.java71
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java383
-rw-r--r--src/com/android/settings/bluetooth/MapProfile.java213
-rwxr-xr-xsrc/com/android/settings/bluetooth/OppProfile.java89
-rwxr-xr-xsrc/com/android/settings/bluetooth/PanProfile.java183
-rwxr-xr-xsrc/com/android/settings/bluetooth/PbapServerProfile.java152
-rw-r--r--src/com/android/settings/bluetooth/RequestPermissionActivity.java9
-rw-r--r--src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java4
-rwxr-xr-xsrc/com/android/settings/bluetooth/Utils.java34
-rw-r--r--src/com/android/settings/deviceinfo/UsbSettings.java15
-rw-r--r--src/com/android/settings/drawable/CircleFramedDrawable.java59
-rw-r--r--src/com/android/settings/fuelgauge/BatteryHistoryChart.java5
-rw-r--r--src/com/android/settings/notification/AppNotificationSettings.java27
-rw-r--r--src/com/android/settings/notification/NotificationAppList.java4
-rw-r--r--src/com/android/settings/notification/ZenModeSettings.java2
-rw-r--r--src/com/android/settings/print/PrintSettingsUtils.java7
-rw-r--r--src/com/android/settings/quicklaunch/BookmarkPicker.java331
-rw-r--r--src/com/android/settings/quicklaunch/QuickLaunchSettings.java370
-rw-r--r--src/com/android/settings/quicklaunch/ShortcutPreference.java151
-rw-r--r--src/com/android/settings/search/Index.java21
-rw-r--r--src/com/android/settings/sim/SimDialogActivity.java7
-rw-r--r--src/com/android/settings/sim/SimSettings.java3
-rw-r--r--src/com/android/settings/users/AppRestrictionsFragment.java154
-rw-r--r--src/com/android/settings/users/EditUserInfoController.java13
-rw-r--r--src/com/android/settings/users/RestrictedProfileSettings.java7
-rw-r--r--src/com/android/settings/users/UserDetailsSettings.java49
-rw-r--r--src/com/android/settings/users/UserDialogs.java99
-rw-r--r--src/com/android/settings/users/UserPreference.java24
-rw-r--r--src/com/android/settings/users/UserSettings.java119
-rw-r--r--src/com/android/settings/voice/VoiceInputHelper.java6
-rw-r--r--src/com/android/settings/voice/VoiceInputSettings.java11
-rw-r--r--src/com/android/settings/widget/SettingsAppWidgetProvider.java7
-rw-r--r--src/com/android/settings/wifi/AccessPoint.java719
-rw-r--r--src/com/android/settings/wifi/AccessPointPreference.java165
-rw-r--r--src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java93
-rw-r--r--src/com/android/settings/wifi/Summary.java44
-rw-r--r--src/com/android/settings/wifi/WifiApEnabler.java62
-rw-r--r--src/com/android/settings/wifi/WifiConfigController.java68
-rw-r--r--src/com/android/settings/wifi/WifiConfigUiBase.java3
-rw-r--r--src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java210
-rw-r--r--src/com/android/settings/wifi/WifiDialog.java1
-rw-r--r--src/com/android/settings/wifi/WifiEnabler.java4
-rw-r--r--src/com/android/settings/wifi/WifiSettings.java401
-rw-r--r--src/com/android/settings/wifi/WifiSettingsForSetupWizard.java56
-rw-r--r--src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java769
-rw-r--r--src/com/android/settings/wifi/WifiStatusTest.java27
-rw-r--r--src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java7
123 files changed, 4507 insertions, 9307 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/AppHeader.java b/src/com/android/settings/AppHeader.java
new file mode 100644
index 0000000..cd76e80
--- /dev/null
+++ b/src/com/android/settings/AppHeader.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class AppHeader {
+
+ public static void createAppHeader(final Activity activity, Drawable icon, CharSequence label,
+ final Intent settingsIntent) {
+ final View content = activity.findViewById(R.id.main_content);
+ final ViewGroup contentParent = (ViewGroup) content.getParent();
+ final View bar = activity.getLayoutInflater().inflate(R.layout.app_header,
+ contentParent, false);
+
+ final ImageView appIcon = (ImageView) bar.findViewById(R.id.app_icon);
+ appIcon.setImageDrawable(icon);
+
+ final TextView appName = (TextView) bar.findViewById(R.id.app_name);
+ appName.setText(label);
+
+ final View appSettings = bar.findViewById(R.id.app_settings);
+ if (settingsIntent == null) {
+ appSettings.setVisibility(View.GONE);
+ } else {
+ appSettings.setClickable(true);
+ appSettings.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ activity.startActivity(settingsIntent);
+ }
+ });
+ }
+ contentParent.addView(bar, 0);
+ }
+
+}
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index b289e7a..aeb3827 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -35,6 +35,8 @@ import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.security.KeyStore;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
import android.util.EventLog;
import android.util.Log;
import android.util.MutableBoolean;
@@ -72,44 +74,42 @@ public class ChooseLockGeneric extends SettingsActivity {
}
public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
+ private static final String TAG = "ChooseLockGenericFragment";
private static final int MIN_PASSWORD_LENGTH = 4;
- 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 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 HIDE_DISABLED_PREFS = "hide_disabled_prefs";
public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
- private static final boolean ALWAY_SHOW_TUTORIAL = true;
+ private static final int CONFIRM_EXISTING_REQUEST = 100;
+ private static final int ENABLE_ENCRYPTION_REQUEST = 101;
+ private static final int CHOOSE_LOCK_REQUEST = 102;
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private DevicePolicyManager mDPM;
private KeyStore mKeyStore;
private boolean mPasswordConfirmed = false;
private boolean mWaitingForConfirmation = false;
- private boolean mFinishPending = false;
private int mEncryptionRequestQuality;
private boolean mEncryptionRequestDisabled;
private boolean mRequirePassword;
private LockPatternUtils mLockPatternUtils;
+ private FingerprintManager mFingerprintManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mFingerprintManager =
+ (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE);
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mKeyStore = KeyStore.getInstance();
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
@@ -125,7 +125,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 +145,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 +185,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 +211,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 +221,23 @@ 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 boolean hideDisabledPrefs = intent.getBooleanExtra(
+ HIDE_DISABLED_PREFS, false);
final PreferenceScreen prefScreen = getPreferenceScreen();
if (prefScreen != null) {
prefScreen.removeAll();
}
addPreferencesFromResource(R.xml.security_settings_picker);
- disableUnusablePreferences(quality, allowBiometric);
+ disableUnusablePreferences(quality, hideDisabledPrefs);
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 +266,23 @@ public class ChooseLockGeneric extends SettingsActivity {
* implementation is in disableUnusablePreferenceImpl.
*
* @param quality the requested quality.
- * @param allowBiometric whether to allow biometic screen lock.
+ * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
+ * they're not shown at all.
*/
- protected void disableUnusablePreferences(final int quality,
- MutableBoolean allowBiometric) {
- disableUnusablePreferencesImpl(quality, allowBiometric, false /* hideDisabled */);
+ protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
+ disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
}
/***
* 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 +300,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 +310,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 +346,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 +379,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,41 +388,46 @@ 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);
+ removeAllFingerprintTemplates();
getActivity().setResult(Activity.RESULT_OK);
finish();
} else {
+ removeAllFingerprintTemplates();
finish();
}
}
+ // TODO: This is only required because we used to enforce clients have a listener,
+ // which is no longer required in the new API. Remove when that happens.
+ FingerprintManagerReceiver mReceiver = new FingerprintManagerReceiver() {
+ public void onRemoved(int fingerprintId) {
+ Log.v(TAG, "onRemoved(id=" + fingerprintId + ")");
+ }
+ };
+
+ private void removeAllFingerprintTemplates() {
+ if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
+ mFingerprintManager.startListening(mReceiver);
+ mFingerprintManager.remove(0 /* all fingerprint templates */);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mFingerprintManager.stopListening();
+ }
+
@Override
protected int getHelpResource() {
return R.string.help_url_choose_lockscreen;
@@ -526,9 +463,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..0a0aebd 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,11 @@ 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);
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/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 60803dc..45d3d11 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -135,7 +135,13 @@ public final class CredentialStorage extends Activity {
handleUnlockOrInstall();
}
} else {
- finish();
+ // Users can set a screen lock if there is none even if they can't modify the
+ // credentials store.
+ if (ACTION_UNLOCK.equals(action) && mKeyStore.state() == KeyStore.State.UNINITIALIZED) {
+ ensureKeyGuard();
+ } else {
+ finish();
+ }
}
}
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..b5b33f4 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;
@@ -133,8 +138,8 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private static final String TRANSITION_ANIMATION_SCALE_KEY = "transition_animation_scale";
private static final String ANIMATOR_DURATION_SCALE_KEY = "animator_duration_scale";
private static final String OVERLAY_DISPLAY_DEVICES_KEY = "overlay_display_devices";
+ private static final String ENABLE_MULTI_WINDOW_KEY = "enable_multi_window";
private static final String DEBUG_DEBUGGING_CATEGORY_KEY = "debug_debugging_category";
- private static final String DEBUG_APPLICATIONS_CATEGORY_KEY = "debug_applications_category";
private static final String WIFI_DISPLAY_CERTIFICATION_KEY = "wifi_display_certification";
private static final String WIFI_VERBOSE_LOGGING_KEY = "wifi_verbose_logging";
private static final String WIFI_AGGRESSIVE_HANDOVER_KEY = "wifi_aggressive_handover";
@@ -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";
@@ -153,8 +160,6 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private static final String PROCESS_STATS = "proc_stats";
- private static final String TAG_CONFIRM_ENFORCE = "confirm_enforce";
-
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String TERMINAL_APP_PACKAGE = "com.android.terminal";
@@ -167,6 +172,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private static String DEFAULT_LOG_RING_BUFFER_SIZE_IN_BYTES = "262144"; // 256K
+ private static final String MULTI_WINDOW_SYSTEM_PROPERTY = "persist.sys.debug.multi_window";
private IWindowManager mWindowManager;
private IBackupManager mBackupManager;
private DevicePolicyManager mDpm;
@@ -204,6 +210,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private SwitchPreference mShowTouches;
private SwitchPreference mShowScreenUpdates;
private SwitchPreference mDisableOverlays;
+ private SwitchPreference mEnableMultiWindow;
private SwitchPreference mShowCpuUsage;
private SwitchPreference mForceHardwareUi;
private SwitchPreference mForceMsaa;
@@ -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;
@@ -269,7 +277,6 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
final PreferenceGroup debugDebuggingCategory = (PreferenceGroup)
findPreference(DEBUG_DEBUGGING_CATEGORY_KEY);
-
mEnableAdb = findAndInitSwitchPref(ENABLE_ADB);
mClearAdbKeys = findPreference(CLEAR_ADB_KEYS);
if (!SystemProperties.getBoolean("ro.adb.secure", false)) {
@@ -337,11 +344,24 @@ 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);
mAnimatorDurationScale = addListPreference(ANIMATOR_DURATION_SCALE_KEY);
mOverlayDisplayDevices = addListPreference(OVERLAY_DISPLAY_DEVICES_KEY);
+ mEnableMultiWindow = findAndInitSwitchPref(ENABLE_MULTI_WINDOW_KEY);
+ if (!showEnableMultiWindowPreference()) {
+ final PreferenceGroup drawingGroup =
+ (PreferenceGroup)findPreference("debug_drawing_category");
+ if (drawingGroup != null) {
+ drawingGroup.removePreference(mEnableMultiWindow);
+ } else {
+ mEnableMultiWindow.setEnabled(false);
+ }
+ removePreference(mEnableMultiWindow);
+ mEnableMultiWindow = null;
+ }
mOpenGLTraces = addListPreference(OPENGL_TRACES_KEY);
mSimulateColorSpace = addListPreference(SIMULATE_COLOR_SPACE);
mUseAwesomePlayer = findAndInitSwitchPref(USE_AWESOMEPLAYER_KEY);
@@ -419,6 +439,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private void removePreference(Preference preference) {
getPreferenceScreen().removePreference(preference);
mAllPrefs.remove(preference);
+ mResetSwitchPrefs.remove(preference);
}
private void setPrefsEnabledState(boolean enabled) {
@@ -474,6 +495,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 +512,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
}
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchBar.hide();
+ getActivity().unregisterReceiver(mUsbReceiver);
}
void updateSwitchPreference(SwitchPreference switchPreference, boolean value) {
@@ -531,6 +562,10 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
updateDebugLayoutOptions();
updateAnimationScaleOptions();
updateOverlayDisplayDevicesOptions();
+ if (mEnableMultiWindow != null) {
+ updateSwitchPreference(mEnableMultiWindow,
+ SystemProperties.getBoolean(MULTI_WINDOW_SYSTEM_PROPERTY, false));
+ }
updateOpenGLTracesOptions();
updateImmediatelyDestroyActivitiesOptions();
updateAppProcessLimitOptions();
@@ -693,6 +728,15 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
return !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
}
+ private static boolean showEnableMultiWindowPreference() {
+ return !"user".equals(Build.TYPE);
+ }
+
+ private void setEnableMultiWindow(boolean value) {
+ SystemProperties.set(MULTI_WINDOW_SYSTEM_PROPERTY, String.valueOf(value));
+ pokeSystemProperties();
+ }
+
private void updateBugreportOptions() {
if ("user".equals(Build.TYPE)) {
final ContentResolver resolver = getActivity().getContentResolver();
@@ -743,7 +787,8 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
}
private void updatePointerLocationOptions() {
- updateSwitchPreference(mPointerLocation, Settings.System.getInt(getActivity().getContentResolver(),
+ updateSwitchPreference(mPointerLocation,
+ Settings.System.getInt(getActivity().getContentResolver(),
Settings.System.POINTER_LOCATION, 0) != 0);
}
@@ -753,7 +798,8 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
}
private void updateShowTouchesOptions() {
- updateSwitchPreference(mShowTouches, Settings.System.getInt(getActivity().getContentResolver(),
+ updateSwitchPreference(mShowTouches,
+ Settings.System.getInt(getActivity().getContentResolver(),
Settings.System.SHOW_TOUCHES, 0) != 0);
}
@@ -1022,7 +1068,8 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
}
private void updateForceRtlOptions() {
- updateSwitchPreference(mForceRtlLayout, Settings.Global.getInt(getActivity().getContentResolver(),
+ updateSwitchPreference(mForceRtlLayout,
+ Settings.Global.getInt(getActivity().getContentResolver(),
Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0);
}
@@ -1122,8 +1169,45 @@ 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(),
+ updateSwitchPreference(mShowCpuUsage,
+ Settings.Global.getInt(getActivity().getContentResolver(),
Settings.Global.SHOW_PROCESSES, 0) != 0);
}
@@ -1297,6 +1381,24 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
.show();
}
+ private void confirmEnableMultiWindowMode() {
+ DialogInterface.OnClickListener onConfirmListener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ setEnableMultiWindow((which == DialogInterface.BUTTON_POSITIVE) ? true : false);
+ updateAllOptions();
+ }
+ };
+
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.confirm_enable_multi_window_title)
+ .setMessage(R.string.confirm_enable_multi_window_text)
+ .setPositiveButton(R.string.enable_text, onConfirmListener)
+ .setNegativeButton(android.R.string.cancel, onConfirmListener)
+ .create()
+ .show();
+ }
+
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (switchView != mSwitchBar.getSwitch()) {
@@ -1424,6 +1526,12 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
writeShowUpdatesOption();
} else if (preference == mDisableOverlays) {
writeDisableOverlaysOption();
+ } else if (preference == mEnableMultiWindow) {
+ if (mEnableMultiWindow.isChecked()) {
+ confirmEnableMultiWindowMode();
+ } else {
+ setEnableMultiWindow(false);
+ }
} else if (preference == mShowCpuUsage) {
writeCpuUsageOptions();
} else if (preference == mImmediatelyDestroyActivities) {
@@ -1478,6 +1586,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 +1703,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) {
@@ -1663,6 +1781,9 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
if (!showEnableOemUnlockPreference()) {
keys.add(ENABLE_OEM_UNLOCK);
}
+ if (!showEnableMultiWindowPreference()) {
+ keys.add(ENABLE_MULTI_WINDOW_KEY);
+ }
return keys;
}
};
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index ed95500..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;
@@ -259,6 +257,7 @@ public class DeviceAdminAdd extends Activity {
mAdminWarning = (TextView) findViewById(R.id.admin_warning);
mAdminPolicies = (ViewGroup) findViewById(R.id.admin_policies);
mCancelButton = (Button) findViewById(R.id.cancel_button);
+ mCancelButton.setFilterTouchesWhenObscured(true);
mCancelButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER,
@@ -267,6 +266,7 @@ public class DeviceAdminAdd extends Activity {
}
});
mActionButton = (Button) findViewById(R.id.action_button);
+ mActionButton.setFilterTouchesWhenObscured(true);
mActionButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mAdding) {
@@ -384,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() {
@@ -407,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()));
@@ -436,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) {
@@ -478,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/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index ddd6728..337ec23 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -32,6 +32,7 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.Dialog;
+import android.app.UiModeManager;
import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -70,6 +71,7 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
private static final String KEY_DOZE = "doze";
private static final String KEY_AUTO_BRIGHTNESS = "auto_brightness";
private static final String KEY_AUTO_ROTATE = "auto_rotate";
+ private static final String KEY_NIGHT_MODE = "night_mode";
private static final int DLG_GLOBAL_CHANGE_WARNING = 1;
@@ -78,6 +80,7 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
private final Configuration mCurConfig = new Configuration();
private ListPreference mScreenTimeoutPreference;
+ private ListPreference mNightModePreference;
private Preference mScreenSaverPreference;
private SwitchPreference mLiftToWakePreference;
private SwitchPreference mDozePreference;
@@ -165,6 +168,13 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
} else {
removePreference(KEY_AUTO_ROTATE);
}
+
+ mNightModePreference = (ListPreference) findPreference(KEY_NIGHT_MODE);
+ final UiModeManager uiManager = (UiModeManager) getSystemService(
+ Context.UI_MODE_SERVICE);
+ final int currentNightMode = uiManager.getNightMode();
+ mNightModePreference.setValue(String.valueOf(currentNightMode));
+ mNightModePreference.setOnPreferenceChangeListener(this);
}
private static boolean allowAllRotations(Context context) {
@@ -381,6 +391,16 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
boolean value = (Boolean) objValue;
Settings.Secure.putInt(getContentResolver(), DOZE_ENABLED, value ? 1 : 0);
}
+ if (preference == mNightModePreference) {
+ try {
+ final int value = Integer.parseInt((String) objValue);
+ final UiModeManager uiManager = (UiModeManager) getSystemService(
+ Context.UI_MODE_SERVICE);
+ uiManager.setNightMode(value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist night mode setting", e);
+ }
+ }
return true;
}
diff --git a/src/com/android/settings/FingerprintEnroll.java b/src/com/android/settings/FingerprintEnroll.java
new file mode 100644
index 0000000..865fcdc
--- /dev/null
+++ b/src/com/android/settings/FingerprintEnroll.java
@@ -0,0 +1,472 @@
+/*
+ * 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;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.AudioAttributes;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.Vibrator;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * Wizard to enroll a fingerprint
+ */
+public class FingerprintEnroll extends SettingsActivity {
+ /**
+ * Used by the choose fingerprint wizard to indicate the wizard is
+ * finished, and each activity in the wizard should finish.
+ * <p>
+ * Previously, each activity in the wizard would finish itself after
+ * starting the next activity. However, this leads to broken 'Back'
+ * behavior. So, now an activity does not finish itself until it gets this
+ * result.
+ */
+ static final int RESULT_FINISHED = RESULT_FIRST_USER;
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, FingerprintEnrollFragment.class.getName());
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (FingerprintEnrollFragment.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ super.onCreate(savedInstanceState);
+ CharSequence msg = getText(R.string.security_settings_fingerprint_preference_title);
+ setTitle(msg);
+ }
+
+ public static class FingerprintEnrollFragment extends Fragment implements View.OnClickListener {
+ private static final int PROGRESS_BAR_MAX = 10000;
+ private static final String TAG = "FingerprintEnroll";
+ private static final boolean DEBUG = true;
+ private static final int CONFIRM_REQUEST = 101;
+ private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
+ private static final long ENROLL_TIMEOUT = 300*1000;
+ private static final int FINISH_DELAY = 250;
+
+ private PowerManager mPowerManager;
+ private FingerprintManager mFingerprintManager;
+ private View mContentView;
+ private TextView mTitleText;
+ private TextView mMessageText;
+ private Stage mStage;
+ private int mEnrollmentSteps;
+ private boolean mEnrolling;
+ private Vibrator mVibrator;
+ private ProgressBar mProgressBar;
+ private ImageView mFingerprintAnimator;
+ private ObjectAnimator mProgressAnim;
+
+ // Give the user a chance to see progress completed before jumping to the next stage.
+ Runnable mDelayedFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ updateStage(Stage.EnrollingFinish);
+ }
+ };
+
+ private final AnimatorListener mProgressAnimationListener = new AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
+ mContentView.postDelayed(mDelayedFinishRunnable, FINISH_DELAY);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) { }
+ };
+
+ // This contains a list of all views managed by the UI. Used to determine which views
+ // need to be shown/hidden at each stage. It should be the union of the lists that follow
+ private static final int MANAGED_VIEWS[] = {
+ R.id.fingerprint_sensor_location,
+ R.id.fingerprint_animator,
+ R.id.fingerprint_enroll_button_area,
+ R.id.fingerprint_in_app_indicator,
+ R.id.fingerprint_enroll_button_add,
+ R.id.fingerprint_enroll_button_next,
+ R.id.fingerprint_progress_bar
+ };
+
+ private static final int VIEWS_ENROLL_ONBOARD[] = {
+ R.id.fingerprint_enroll_button_area,
+ R.id.fingerprint_enroll_button_next
+ };
+
+ private static final int VIEWS_ENROLL_FIND_SENSOR[] = {
+ R.id.fingerprint_sensor_location,
+ R.id.fingerprint_enroll_button_area,
+ R.id.fingerprint_enroll_button_next
+ };
+
+ private static final int VIEWS_ENROLL_START[] = {
+ R.id.fingerprint_animator,
+ };
+
+ private static final int VIEWS_ENROLL_REPEAT[] = {
+ R.id.fingerprint_animator,
+ R.id.fingerprint_progress_bar
+ };
+
+ private static final int VIEWS_ENROLL_FINISH[] = {
+ R.id.fingerprint_enroll_button_area,
+ R.id.fingerprint_in_app_indicator,
+ R.id.fingerprint_enroll_button_add,
+ R.id.fingerprint_enroll_button_next
+ };
+ private static final boolean ALWAYS_SHOW_FIND_SCREEN = true;
+
+ private enum Stage {
+ EnrollingOnboard(R.string.security_settings_fingerprint_enroll_onboard_title,
+ R.string.security_settings_fingerprint_enroll_onboard_message,
+ VIEWS_ENROLL_ONBOARD),
+ EnrollingFindSensor(R.string.security_settings_fingerprint_enroll_find_sensor_title,
+ R.string.security_settings_fingerprint_enroll_find_sensor_message,
+ VIEWS_ENROLL_FIND_SENSOR),
+ EnrollingStart(R.string.security_settings_fingerprint_enroll_start_title,
+ R.string.security_settings_fingerprint_enroll_start_message,
+ VIEWS_ENROLL_START),
+ EnrollingRepeat(R.string.security_settings_fingerprint_enroll_repeat_title,
+ R.string.security_settings_fingerprint_enroll_repeat_message,
+ VIEWS_ENROLL_REPEAT),
+ EnrollingFinish(R.string.security_settings_fingerprint_enroll_finish_title,
+ R.string.security_settings_fingerprint_enroll_finish_message,
+ VIEWS_ENROLL_FINISH);
+
+ Stage(int title, int message, int[] enabledViewIds) {
+ this.title = title;
+ this.message = message;
+ this.enabledViewIds = enabledViewIds;
+ }
+
+ public int title;
+ public int message;
+ public int[] enabledViewIds;
+ };
+
+ void updateStage(Stage stage) {
+ if (DEBUG) Log.v(TAG, "updateStage(" + stage.toString() + ")");
+
+ // Show/hide views
+ for (int i = 0; i < MANAGED_VIEWS.length; i++) {
+ mContentView.findViewById(MANAGED_VIEWS[i]).setVisibility(View.INVISIBLE);
+ }
+ for (int i = 0; i < stage.enabledViewIds.length; i++) {
+ mContentView.findViewById(stage.enabledViewIds[i]).setVisibility(View.VISIBLE);
+ }
+
+ setTitleMessage(stage.title);
+ setMessage(stage.message);
+
+ if (mStage != stage) {
+ onStageChanged(stage);
+ mStage = stage;
+ }
+ }
+
+ private void startFingerprintAnimator() {
+ final Drawable d = mFingerprintAnimator.getDrawable();
+ if (d instanceof AnimationDrawable) {
+ ((AnimationDrawable) d).start();
+ }
+ }
+
+ private void stopFingerprintAnimator() {
+ final Drawable d = mFingerprintAnimator.getDrawable();
+ if (d instanceof AnimationDrawable) {
+ final AnimationDrawable drawable = (AnimationDrawable) d;
+ drawable.stop();
+ drawable.setLevel(0);
+ }
+ }
+
+ private void onStageChanged(Stage stage) {
+ // Update state
+ switch (stage) {
+ case EnrollingOnboard: // pass through
+ case EnrollingFindSensor:
+ mEnrollmentSteps = -1;
+ mEnrolling = false;
+ mFingerprintManager.stopListening();
+ break;
+
+ case EnrollingStart:
+ mEnrollmentSteps = -1;
+ mFingerprintManager.startListening(mReceiver);
+ mFingerprintManager.enroll(ENROLL_TIMEOUT);
+ mProgressBar.setProgress(0);
+ mEnrolling = true;
+ startFingerprintAnimator(); // XXX hack - this should follow fingerprint detection
+ break;
+
+ case EnrollingRepeat:
+ break;
+
+ case EnrollingFinish:
+ stopFingerprintAnimator(); // XXX hack - this should follow fingerprint detection
+ mFingerprintManager.stopListening();
+ mEnrolling = false;
+ break;
+
+ default:
+ mFingerprintManager.stopListening();
+ break;
+ }
+ }
+
+ private void cancelEnrollment() {
+ if (mEnrolling) {
+ if (DEBUG) Log.v(TAG, "Cancel enrollment\n");
+ mFingerprintManager.enrollCancel();
+ mEnrolling = false;
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ // Do a little cleanup
+ cancelEnrollment();
+ mFingerprintManager.stopListening();
+ }
+
+ private void updateProgress(int progress) {
+ if (DEBUG) Log.v(TAG, "Progress: " + progress);
+ if (mVibrator != null) {
+ mVibrator.vibrate(100, new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build());
+ }
+ if (mProgressAnim != null) {
+ mProgressAnim.cancel();
+ }
+ ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, "progress",
+ mProgressBar.getProgress(), progress);
+ anim.addListener(mProgressAnimationListener);
+ anim.start();
+ mProgressAnim = anim;
+ }
+
+ private void setMessage(int id) {
+ if (id != 0) mMessageText.setText(id);
+ }
+
+ private void setTitleMessage(int title) {
+ if (title != 0) mTitleText.setText(title);
+ }
+
+ private FingerprintManagerReceiver mReceiver = new FingerprintManagerReceiver() {
+ public void onEnrollResult(int fingerprintId, int remaining) {
+ if (DEBUG) Log.v(TAG, "onEnrollResult(id=" + fingerprintId + ", rem=" + remaining);
+ if (mEnrollmentSteps == -1) {
+ mEnrollmentSteps = remaining;
+ updateStage(Stage.EnrollingRepeat);
+ }
+ if (remaining >= 0) {
+ int progress = Math.max(0, mEnrollmentSteps + 1 - remaining);
+ updateProgress(PROGRESS_BAR_MAX * progress / (mEnrollmentSteps + 1));
+ // Treat fingerprint like a touch event
+ mPowerManager.userActivity(SystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS);
+ }
+ }
+
+ public void onError(int error) {
+ switch(error) {
+ case FingerprintManager.FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+ setMessage(R.string.fingerprint_error_unable_to_process);
+ break;
+ case FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE:
+ setMessage(R.string.fingerprint_error_hw_not_available);
+ break;
+ case FingerprintManager.FINGERPRINT_ERROR_NO_SPACE:
+ setMessage(R.string.fingerprint_error_no_space);
+ break;
+ case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
+ setMessage(R.string.fingerprint_error_timeout);
+ break;
+ case FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER:
+ Log.w(TAG, "Receiver not registered");
+ break;
+ }
+ }
+
+ public void onRemoved(int fingerprintId) {
+ if (DEBUG) Log.v(TAG, "onRemoved(id=" + fingerprintId + ")");
+ }
+
+ @Override
+ public void onProcessed(int fingerprintId) {
+ if (DEBUG) Log.v(TAG, "onProcessed(id=" + fingerprintId + ")");
+ }
+
+ public void onAcquired(int scanInfo) {
+ int msgId = 0;
+ startFingerprintAnimator();
+ switch(scanInfo) {
+ case FingerprintManager.FINGERPRINT_ACQUIRED_GOOD:
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+ msgId = R.string.fingerprint_acquired_imager_dirty;
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED_TOO_SLOW:
+ msgId = R.string.fingerprint_acquired_too_fast;
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST:
+ msgId = R.string.fingerprint_acquired_too_slow;
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL:
+ case FingerprintManager.FINGERPRINT_ACQUIRED_INSUFFICIENT:
+ msgId = R.string.fingerprint_acquired_try_again;
+ break;
+ default:
+ // Try not to be too verbose in the UI. The user just needs to try again.
+ // Log the message so we can dig into the issue if necessary.
+ Log.w(TAG, "Try again because scanInfo was " + scanInfo);
+ msgId = R.string.fingerprint_acquired_try_again;
+ break;
+ }
+ setMessage(msgId);
+ }
+ };
+
+ private boolean runConfirmDeviceCredentials(int request) {
+ if (DEBUG) Log.v(TAG, "runKeyguardConfirmation(" + request + ")");
+ Resources res = getResources();
+ return new ChooseLockSettingsHelper(getActivity(), this)
+ .launchConfirmationActivity(request,
+ res.getText(R.string.master_clear_gesture_prompt),
+ res.getText(R.string.master_clear_gesture_explanation));
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
+ if (resultCode == RESULT_FINISHED) {
+ // The lock pin/pattern/password was set. Start enrolling!
+ updateStage(Stage.EnrollingFindSensor);
+ }
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ mFingerprintManager = (FingerprintManager)activity
+ .getSystemService(Context.FINGERPRINT_SERVICE);
+ mVibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
+ mPowerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
+
+ mContentView = inflater.inflate(R.layout.fingerprint_enroll, null);
+ mTitleText = (TextView) mContentView.findViewById(R.id.fingerprint_enroll_title);
+ mMessageText = (TextView) mContentView.findViewById(R.id.fingerprint_enroll_message);
+ mProgressBar = (ProgressBar) mContentView.findViewById(R.id.fingerprint_progress_bar);
+ mFingerprintAnimator = (ImageView) mContentView.findViewById(R.id.fingerprint_animator);
+
+ final int buttons[] = {
+ R.id.fingerprint_enroll_button_add,
+ R.id.fingerprint_enroll_button_next };
+ for (int i = 0; i < buttons.length; i++) {
+ mContentView.findViewById(buttons[i]).setOnClickListener(this);
+ }
+
+ LockPatternUtils utils = new LockPatternUtils(activity);
+ if (!utils.isSecure()) {
+ // Device doesn't have any security. Set that up first.
+ updateStage(Stage.EnrollingOnboard);
+ } else if (ALWAYS_SHOW_FIND_SCREEN
+ || mFingerprintManager.getEnrolledFingerprints().size() == 0) {
+ updateStage(Stage.EnrollingFindSensor);
+ } else {
+ updateStage(Stage.EnrollingStart);
+ }
+ return mContentView;
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch(v.getId()) {
+ case R.id.fingerprint_enroll_button_add:
+ updateStage(Stage.EnrollingStart);
+ break;
+ case R.id.fingerprint_enroll_button_next:
+ if (mStage == Stage.EnrollingOnboard) {
+ launchChooseLock();
+ } else if (mStage == Stage.EnrollingFindSensor) {
+ updateStage(Stage.EnrollingStart);
+ } else if (mStage == Stage.EnrollingFinish) {
+ getActivity().finish();
+ } else {
+ Log.v(TAG, "No idea what to do next!");
+ }
+ break;
+ }
+ }
+
+ private void launchChooseLock() {
+ Intent intent = new Intent();
+ intent.setClassName("com.android.settings", ChooseLockGeneric.class.getName());
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
+ }
+ }
+}
diff --git a/src/com/android/settings/FingerprintSettings.java b/src/com/android/settings/FingerprintSettings.java
new file mode 100644
index 0000000..f91fcfa
--- /dev/null
+++ b/src/com/android/settings/FingerprintSettings.java
@@ -0,0 +1,235 @@
+/*
+ * 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;
+
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.FingerprintItem;
+import android.util.Log;
+import android.widget.EditText;
+
+import com.android.settings.search.Indexable;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Settings screen for fingerprints
+ */
+public class FingerprintSettings extends SettingsActivity {
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, FingerprintSettingsFragment.class.getName());
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (FingerprintSettingsFragment.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CharSequence msg = getText(R.string.security_settings_fingerprint_preference_title);
+ setTitle(msg);
+ }
+
+ public static class FingerprintSettingsFragment extends SettingsPreferenceFragment
+ implements OnPreferenceChangeListener, Indexable {
+ private static final String TAG = "FingerprintSettings";
+ private static final String KEY_FINGERPRINT_ITEM = "key_fingerprint_item";
+ private static final String KEY_USAGE_CATEGORY = "fingerprint_usage_category";
+ private static final String KEY_FINGERPRINT_ADD = "key_fingerprint_add";
+ private static final String KEY_MANAGE_CATEGORY = "fingerprint_manage_category";
+ private static final String KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE =
+ "fingerprint_enable_keyguard_toggle";
+
+ private static final int ADD_FINGERPRINT_REQUEST = 10;
+
+ private static final boolean ENABLE_USAGE_CATEGORY = false;
+
+ private FingerprintManager mFingerprintManager;
+ private HashMap<Preference, FingerprintItem> mFingerprintMap
+ = new HashMap<Preference, FingerprintManager.FingerprintItem>();
+ private EditText mDialogTextField;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mFingerprintManager = (FingerprintManager) getActivity().getSystemService(
+ Context.FINGERPRINT_SERVICE);
+ mFingerprintManager.startListening(new FingerprintManagerReceiver() {
+ @Override
+ public void onRemoved(int fingerprintId) {
+ Log.v(TAG, "Fingerprint template " + fingerprintId + " removed");
+ // TODO: this is a bit wasteful; just remove the fingerprint id item
+ createPreferenceHierarchy();
+ }
+ @Override
+ public void onProcessed(int fingerprintId) {
+ Log.v(TAG, "Fingerprint " + fingerprintId + " detected");
+ }
+ });
+ }
+
+ /**
+ * Important!
+ *
+ * Don't forget to update the SecuritySearchIndexProvider if you are doing any change in the
+ * logic or adding/removing preferences here.
+ */
+ private PreferenceScreen createPreferenceHierarchy() {
+ PreferenceScreen root = getPreferenceScreen();
+ if (root != null) {
+ root.removeAll();
+ }
+ addPreferencesFromResource(R.xml.security_settings_fingerprint);
+ root = getPreferenceScreen();
+
+ // Fingerprint items
+ PreferenceGroup manageCategory = (PreferenceGroup) root.findPreference(
+ KEY_MANAGE_CATEGORY);
+ if (manageCategory != null) {
+ addFingerprintItemPreferences(manageCategory);
+ }
+
+ // Fingerprint usage options
+ PreferenceGroup usageCategory = (PreferenceGroup) root.findPreference(
+ KEY_USAGE_CATEGORY);
+ if (usageCategory != null) {
+ Preference toggle = root.findPreference(KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE);
+ toggle.setOnPreferenceChangeListener(this);
+ if (!ENABLE_USAGE_CATEGORY) {
+ root.removePreference(usageCategory);
+ } else {
+ toggle.setOnPreferenceChangeListener(this);
+ }
+ }
+
+ return root;
+ }
+
+ private void addFingerprintItemPreferences(PreferenceGroup manageFingerprintCategory) {
+ manageFingerprintCategory.removeAll();
+ List<FingerprintItem> items = mFingerprintManager.getEnrolledFingerprints();
+ final int fingerprintCount = items.size();
+ mFingerprintMap.clear();
+ for (int i = 0; i < fingerprintCount; i++) {
+ Preference pref = new Preference(manageFingerprintCategory.getContext());
+ pref.setKey(KEY_FINGERPRINT_ITEM);
+ FingerprintItem item = items.get(i);
+ pref.setTitle(item.name);
+ manageFingerprintCategory.addPreference(pref);
+ pref.setOnPreferenceChangeListener(this);
+ mFingerprintMap.put(pref, item);
+ }
+ Preference addPreference = new Preference(manageFingerprintCategory.getContext());
+ addPreference.setKey(KEY_FINGERPRINT_ADD);
+ addPreference.setTitle(R.string.fingerprint_add_title);
+ manageFingerprintCategory.addPreference(addPreference);
+ addPreference.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Make sure we reload the preference hierarchy since fingerprints may be added,
+ // deleted or renamed.
+ createPreferenceHierarchy();
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
+ final String key = pref.getKey();
+ if (KEY_FINGERPRINT_ADD.equals(key)) {
+ Intent intent = new Intent();
+ intent.setClassName("com.android.settings", FingerprintEnroll.class.getName());
+ startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
+ } else if (KEY_FINGERPRINT_ITEM.equals(key)) {
+ final FingerprintItem item = mFingerprintMap.get(pref);
+ showRenameDeleteDialog(item.name, pref, item.id);
+ return super.onPreferenceTreeClick(preferenceScreen, pref);
+ }
+ return true;
+ }
+
+ private void showRenameDeleteDialog(final CharSequence name, Preference pref,
+ final int fpId) {
+ final Activity activity = getActivity();
+ AlertDialog dialog = new AlertDialog.Builder(activity)
+ .setView(R.layout.fingerprint_rename_dialog)
+ .setPositiveButton(R.string.security_settings_fingerprint_enroll_dialog_ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String newName = mDialogTextField.getText().toString();
+ if (!newName.equals(name)) {
+ Log.v(TAG, "Would rename " + name + " to " + newName);
+ mFingerprintManager.rename(fpId, newName);
+ }
+ dialog.dismiss();
+ }
+ })
+ .setNegativeButton(R.string.security_settings_fingerprint_enroll_dialog_delete,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.v(TAG, "Removing fpId " + fpId);
+ mFingerprintManager.remove(fpId);
+ dialog.dismiss();
+ }
+ })
+ .create();
+ dialog.show();
+ mDialogTextField = (EditText) dialog.findViewById(R.id.fingerprint_rename_field);
+ mDialogTextField.setText(name);
+ mDialogTextField.selectAll();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ boolean result = true;
+ final String key = preference.getKey();
+ if (KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE.equals(key)) {
+ // TODO
+ } else {
+ Log.v(TAG, "Unknown key:" + key);
+ }
+ return result;
+ }
+
+ @Override
+ protected int getHelpResource() {
+ return R.string.help_url_security;
+ }
+ }
+}
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/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index a296564..77927d9 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -18,7 +18,6 @@ package com.android.settings;
import android.app.Activity;
import android.app.QueuedWork;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -59,10 +58,8 @@ import com.android.internal.telephony.TelephonyProperties;
import com.android.ims.ImsConfig;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.io.IOException;
import java.net.UnknownHostException;
@@ -754,18 +751,22 @@ public class RadioInfo extends Activity {
* This function checks for basic functionality of HTTP Client.
*/
private void httpClientTest() {
- HttpClient client = new DefaultHttpClient();
+ HttpURLConnection urlConnection = null;
try {
- HttpGet request = new HttpGet("http://www.google.com");
- HttpResponse response = client.execute(request);
- if (response.getStatusLine().getStatusCode() == 200) {
+ // TODO: Hardcoded for now, make it UI configurable
+ URL url = new URL("http://www.google.com");
+ urlConnection = (HttpURLConnection) url.openConnection();
+ if (urlConnection.getResponseCode() == 200) {
mHttpClientTestResult = "Pass";
} else {
- mHttpClientTestResult = "Fail: Code: " + String.valueOf(response);
+ mHttpClientTestResult = "Fail: Code: " + urlConnection.getResponseMessage();
}
- request.abort();
} catch (IOException e) {
mHttpClientTestResult = "Fail: IOException";
+ } finally {
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
}
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index c2990e5..053e7f0 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -41,6 +41,8 @@ import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.security.KeyStore;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManager.FingerprintItem;
import android.service.trust.TrustAgentService;
import android.telephony.TelephonyManager;
import android.telephony.SubscriptionManager;
@@ -65,17 +67,14 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
*/
public class SecuritySettings extends SettingsPreferenceFragment
implements OnPreferenceChangeListener, DialogInterface.OnClickListener, Indexable {
+
+ private static final String TAG = "SecuritySettings";
private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
- static final String TAG = "SecuritySettings";
private static final Intent TRUST_AGENT_INTENT =
new Intent(TrustAgentService.SERVICE_INTERFACE);
// 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";
@@ -83,10 +82,9 @@ public class SecuritySettings extends SettingsPreferenceFragment
private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings";
private static final String KEY_ADVANCED_SECURITY = "advanced_security";
private static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents";
+ private static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings";
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 +102,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 +115,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
private LockPatternUtils mLockPatternUtils;
private ListPreference mLockAfter;
- private SwitchPreference mBiometricWeakLiveliness;
private SwitchPreference mVisiblePattern;
private SwitchPreference mShowPassword;
@@ -165,9 +162,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:
@@ -230,32 +224,12 @@ public class SecuritySettings extends SettingsPreferenceFragment
}
}
- // Trust Agent preferences
+ // Fingerprint and trust agents
PreferenceGroup securityCategory = (PreferenceGroup)
root.findPreference(KEY_SECURITY_CATEGORY);
if (securityCategory != null) {
- final boolean hasSecurity = mLockPatternUtils.isSecure();
- ArrayList<TrustAgentComponentInfo> agents =
- getActiveTrustAgents(getPackageManager(), mLockPatternUtils);
- for (int i = 0; i < agents.size(); i++) {
- final TrustAgentComponentInfo agent = agents.get(i);
- Preference trustAgentPreference =
- new Preference(securityCategory.getContext());
- trustAgentPreference.setKey(KEY_TRUST_AGENT);
- trustAgentPreference.setTitle(agent.title);
- trustAgentPreference.setSummary(agent.summary);
- // Create intent for this preference.
- Intent intent = new Intent();
- intent.setComponent(agent.componentName);
- intent.setAction(Intent.ACTION_MAIN);
- trustAgentPreference.setIntent(intent);
- // Add preference to the settings menu.
- securityCategory.addPreference(trustAgentPreference);
- if (!hasSecurity) {
- trustAgentPreference.setEnabled(false);
- trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
- }
- }
+ maybeAddFingerprintPreference(securityCategory);
+ addTrustAgentSettings(securityCategory);
}
// lock after preference
@@ -265,10 +239,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 +254,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);
@@ -370,6 +331,59 @@ public class SecuritySettings extends SettingsPreferenceFragment
return root;
}
+ private void maybeAddFingerprintPreference(PreferenceGroup securityCategory) {
+ FingerprintManager fpm = (FingerprintManager) getActivity().getSystemService(
+ Context.FINGERPRINT_SERVICE);
+ if (!fpm.isHardwareDetected()) {
+ Log.v(TAG, "No fingerprint hardware detected!!");
+ return;
+ }
+ Preference fingerprintPreference = new Preference(securityCategory.getContext());
+ fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);
+ fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title);
+ Intent intent = new Intent();
+ List<FingerprintItem> items = fpm.getEnrolledFingerprints();
+ int fingerprintCount = items.size();
+ final String clazz;
+ if (fingerprintCount > 0) {
+ fingerprintPreference.setSummary(getResources().getQuantityString(
+ R.plurals.security_settings_fingerprint_preference_summary,
+ fingerprintCount, fingerprintCount));
+ clazz = FingerprintSettings.class.getName();
+ } else {
+ // No fingerprints registered, launch directly into enrollment wizard
+ clazz = FingerprintEnroll.class.getName();
+ }
+ intent.setClassName("com.android.settings", clazz);
+ fingerprintPreference.setIntent(intent);
+ securityCategory.addPreference(fingerprintPreference);
+ }
+
+ private void addTrustAgentSettings(PreferenceGroup securityCategory) {
+ final boolean hasSecurity = mLockPatternUtils.isSecure();
+ ArrayList<TrustAgentComponentInfo> agents =
+ getActiveTrustAgents(getPackageManager(), mLockPatternUtils);
+ for (int i = 0; i < agents.size(); i++) {
+ final TrustAgentComponentInfo agent = agents.get(i);
+ Preference trustAgentPreference =
+ new Preference(securityCategory.getContext());
+ trustAgentPreference.setKey(KEY_TRUST_AGENT);
+ trustAgentPreference.setTitle(agent.title);
+ trustAgentPreference.setSummary(agent.summary);
+ // Create intent for this preference.
+ Intent intent = new Intent();
+ intent.setComponent(agent.componentName);
+ intent.setAction(Intent.ACTION_MAIN);
+ trustAgentPreference.setIntent(intent);
+ // Add preference to the settings menu.
+ securityCategory.addPreference(trustAgentPreference);
+ if (!hasSecurity) {
+ trustAgentPreference.setEnabled(false);
+ trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
+ }
+ }
+ }
+
/* Return true if a there is a Slot that has Icc.
*/
private boolean isSimIccReady() {
@@ -562,10 +576,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 +599,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 +622,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 +646,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 +671,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 +791,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 ebb7491..b16fe81 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 cbffa86..575fed4 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -43,6 +43,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
@@ -83,7 +84,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;
@@ -302,8 +302,8 @@ public class SettingsActivity extends Activity
NotificationAppList.class.getName(),
AppNotificationSettings.class.getName(),
OtherSoundSettings.class.getName(),
+ ApnSettings.class.getName()
QuickLaunchSettings.class.getName(),
- ApnSettings.class.getName(),
WifiCallingSettings.class.getName()
};
@@ -536,7 +536,12 @@ public class SettingsActivity extends Activity
getFragmentManager().addOnBackStackChangedListener(this);
if (mIsShowingDashboard) {
- Index.getInstance(getApplicationContext()).update();
+ // Run the Index update only if we have some space
+ if (!Utils.isLowStorage(this)) {
+ Index.getInstance(getApplicationContext()).update();
+ } else {
+ Log.w(LOG_TAG, "Cannot update the Indexer as we are running low on storage space!");
+ }
}
if (savedState != null) {
diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java
index 42e2baa..f29f08a 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, boolean hideDisabled) {
// 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..16037c5 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;
@@ -51,6 +52,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.preference.Preference;
import android.preference.PreferenceFrameLayout;
import android.preference.PreferenceGroup;
@@ -65,6 +67,8 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
@@ -130,6 +134,8 @@ public final class Utils {
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+ private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>();
+
/**
* Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference.
@@ -846,43 +852,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 +888,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 +1065,43 @@ 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);
+ }
+
+ /**
+ * Return if we are running low on storage space or not.
+ *
+ * @param context The context
+ * @return true if we are running low on storage space
+ */
+ public static boolean isLowStorage(Context context) {
+ final StorageManager sm = StorageManager.from(context);
+ return (sm.getStorageBytesUntilLow(context.getFilesDir()) < 0);
+ }
+
+
+ /**
+ * Returns a default user icon (as a {@link Bitmap}) for the given user.
+ *
+ * Note that for guest users, you should pass in {@code UserHandle.USER_NULL}.
+ * @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
+ */
+ public static Bitmap getDefaultUserIconAsBitmap(int userId) {
+ Bitmap bitmap = null;
+ // Try finding the corresponding bitmap in the dark bitmap cache
+ bitmap = sDarkDefaultUserBitmapCache.get(userId);
+ if (bitmap == null) {
+ bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, false));
+ // Save it to cache
+ sDarkDefaultUserBitmapCache.put(userId, bitmap);
+ }
+ return bitmap;
+ }
}
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 9152870..71cd322 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -235,16 +235,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/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java
new file mode 100644
index 0000000..81edde2
--- /dev/null
+++ b/src/com/android/settings/applications/AppInfoBase.java
@@ -0,0 +1,203 @@
+/*
+ * 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.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.usb.IUsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.preference.PreferenceFragment;
+import android.util.Log;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+
+public abstract class AppInfoBase extends PreferenceFragment
+ implements ApplicationsState.Callbacks {
+
+ public static final String ARG_PACKAGE_NAME = "package";
+
+ protected static final String TAG = AppInfoBase.class.getSimpleName();
+ protected static final boolean localLOGV = false;
+
+ protected boolean mAppControlRestricted = false;
+
+ protected ApplicationsState mState;
+ private ApplicationsState.Session mSession;
+ protected ApplicationsState.AppEntry mAppEntry;
+ protected PackageInfo mPackageInfo;
+ protected String mPackageName;
+
+ protected IUsbManager mUsbManager;
+ protected DevicePolicyManager mDpm;
+ protected UserManager mUserManager;
+ protected PackageManager mPm;
+
+ // Dialog identifiers used in showDialog
+ protected static final int DLG_BASE = 0;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mState = ApplicationsState.getInstance(getActivity().getApplication());
+ mSession = mState.newSession(this);
+ Context context = getActivity();
+ mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mPm = context.getPackageManager();
+ IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+ mUsbManager = IUsbManager.Stub.asInterface(b);
+
+ // Need to make sure we have loaded applications at this point.
+ mSession.resume();
+
+ retrieveAppEntry();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppControlRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL);
+ mSession.resume();
+
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mSession.pause();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mSession.release();
+ }
+
+ protected String retrieveAppEntry() {
+ final Bundle args = getArguments();
+ mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
+ if (mPackageName == null) {
+ Intent intent = (args == null) ?
+ getActivity().getIntent() : (Intent) args.getParcelable("intent");
+ if (intent != null) {
+ mPackageName = intent.getData().getSchemeSpecificPart();
+ }
+ }
+ mAppEntry = mState.getEntry(mPackageName);
+ if (mAppEntry != null) {
+ // Get application info again to refresh changed properties of application
+ try {
+ mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
+ PackageManager.GET_DISABLED_COMPONENTS |
+ PackageManager.GET_UNINSTALLED_PACKAGES |
+ PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
+ }
+ } else {
+ Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
+ mPackageInfo = null;
+ }
+
+ return mPackageName;
+ }
+
+ protected void setIntentAndFinish(boolean finish, boolean appChanged) {
+ if (localLOGV) Log.i(TAG, "appChanged="+appChanged);
+ Intent intent = new Intent();
+ intent.putExtra(ManageApplications.APP_CHG, appChanged);
+ SettingsActivity sa = (SettingsActivity)getActivity();
+ sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
+ }
+
+ protected void showDialogInner(int id, int moveErrorCode) {
+ DialogFragment newFragment = new MyAlertDialogFragment(id, moveErrorCode);
+ newFragment.setTargetFragment(this, 0);
+ newFragment.show(getFragmentManager(), "dialog " + id);
+ }
+
+ protected abstract boolean refreshUi();
+ protected abstract AlertDialog createDialog(int id, int errorCode);
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ // No op.
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
+ // No op.
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ // No op.
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ // No op.
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ refreshUi();
+ }
+
+ public class MyAlertDialogFragment extends DialogFragment {
+ public MyAlertDialogFragment(int id, int errorCode) {
+ Bundle args = new Bundle();
+ args.putInt("id", id);
+ args.putInt("moveError", errorCode);
+ setArguments(args);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int id = getArguments().getInt("id");
+ int errorCode = getArguments().getInt("moveError");
+ Dialog dialog = createDialog(id, errorCode);
+ if (dialog == null) {
+ throw new IllegalArgumentException("unknown id " + id);
+ }
+ return dialog;
+ }
+ }
+}
diff --git a/src/com/android/settings/applications/AppInfoWithHeader.java b/src/com/android/settings/applications/AppInfoWithHeader.java
new file mode 100644
index 0000000..f7546f2
--- /dev/null
+++ b/src/com/android/settings/applications/AppInfoWithHeader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.os.Bundle;
+import android.util.Log;
+
+import com.android.settings.AppHeader;
+
+public abstract class AppInfoWithHeader extends AppInfoBase {
+
+ private boolean mCreated;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (mCreated) {
+ Log.w(TAG, "onActivityCreated: ignoring duplicate call");
+ return;
+ }
+ mCreated = true;
+ if (mPackageInfo == null) return;
+ AppHeader.createAppHeader(getActivity(), mPackageInfo.applicationInfo.loadIcon(mPm),
+ mPackageInfo.applicationInfo.loadLabel(mPm), null);
+ }
+}
diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java
new file mode 100644
index 0000000..24a6fe0
--- /dev/null
+++ b/src/com/android/settings/applications/AppLaunchSettings.java
@@ -0,0 +1,191 @@
+/*
+ * 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.app.AlertDialog;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.BulletSpan;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListener {
+
+ private Button mActivitiesButton;
+ private AppWidgetManager mAppWidgetManager;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.app_preferred_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+
+ mActivitiesButton = (Button) view.findViewById(R.id.clear_activities_button);
+ mRootView = view;
+
+ return view;
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ boolean hasBindAppWidgetPermission =
+ mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
+
+ TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
+ TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
+ boolean autoLaunchEnabled = hasPreferredActivities(mPm, mPackageName)
+ || hasUsbDefaults(mUsbManager, mPackageName);
+ if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
+ resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
+ } else {
+ boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
+
+ if (hasBindAppWidgetPermission) {
+ autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
+ } else {
+ autoLaunchTitleView.setText(R.string.auto_launch_label);
+ }
+
+ CharSequence text = null;
+ int bulletIndent = getResources()
+ .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
+ if (autoLaunchEnabled) {
+ CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
+ SpannableString s = new SpannableString(autoLaunchEnableText);
+ if (useBullets) {
+ s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
+ }
+ text = (text == null) ?
+ TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
+ }
+ if (hasBindAppWidgetPermission) {
+ CharSequence alwaysAllowBindAppWidgetsText =
+ getText(R.string.always_allow_bind_appwidgets_text);
+ SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
+ if (useBullets) {
+ s.setSpan(new BulletSpan(bulletIndent),
+ 0, alwaysAllowBindAppWidgetsText.length(), 0);
+ }
+ text = (text == null) ?
+ TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
+ }
+ autoLaunchView.setText(text);
+ mActivitiesButton.setEnabled(true);
+ mActivitiesButton.setOnClickListener(this);
+ }
+ return true;
+ }
+
+ private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
+ title.setText(R.string.auto_launch_label);
+ autoLaunchView.setText(R.string.auto_launch_disable_text);
+ // Disable clear activities button
+ mActivitiesButton.setEnabled(false);
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ // No dialogs for preferred launch settings.
+ return null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mActivitiesButton) {
+ if (mUsbManager != null) {
+ mPm.clearPackagePreferredActivities(mPackageName);
+ try {
+ mUsbManager.clearDefaults(mPackageName, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "mUsbManager.clearDefaults", e);
+ }
+ mAppWidgetManager.setBindAppWidgetPermission(mPackageName, false);
+ TextView autoLaunchTitleView =
+ (TextView) mRootView.findViewById(R.id.auto_launch_title);
+ TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
+ resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
+ }
+ }
+ }
+
+ private static boolean hasUsbDefaults(IUsbManager usbManager, String packageName) {
+ try {
+ if (usbManager != null) {
+ return usbManager.hasDefaults(packageName, UserHandle.myUserId());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "mUsbManager.hasDefaults", e);
+ }
+ return false;
+ }
+
+ private static boolean hasPreferredActivities(PackageManager pm, String packageName) {
+ // Get list of preferred activities
+ List<ComponentName> prefActList = Collections.emptyList();
+ // Intent list cannot be null. so pass empty list
+ List<IntentFilter> intentList = Collections.emptyList();
+ pm.getPreferredActivities(intentList, prefActList, packageName);
+ if (localLOGV) {
+ Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
+ }
+ return prefActList.size() > 0;
+ }
+
+ public static CharSequence getSummary(AppEntry appEntry, IUsbManager usbManager,
+ PackageManager pm, Context context) {
+ String packageName = appEntry.info.packageName;
+ boolean hasPreferred = hasPreferredActivities(pm, packageName)
+ || hasUsbDefaults(usbManager, packageName);
+ return context.getString(hasPreferred
+ ? R.string.launch_defaults_some
+ : R.string.launch_defaults_none);
+ }
+
+}
diff --git a/src/com/android/settings/applications/AppPermissionSettings.java b/src/com/android/settings/applications/AppPermissionSettings.java
new file mode 100644
index 0000000..496faf5
--- /dev/null
+++ b/src/com/android/settings/applications/AppPermissionSettings.java
@@ -0,0 +1,222 @@
+/*
+ * 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.app.AlertDialog;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AppSecurityPermissions;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.android.internal.telephony.ISms;
+import com.android.internal.telephony.SmsUsageMonitor;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+
+public class AppPermissionSettings extends AppInfoWithHeader {
+
+ private ISms mSmsManager;
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.permission_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+
+ mRootView = view;
+ return view;
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ // Security permissions section
+ LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
+ AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), mPackageName);
+ int premiumSmsPermission = getPremiumSmsPermission(mPackageName);
+ // Premium SMS permission implies the app also has SEND_SMS permission, so the original
+ // application permissions list doesn't have to be shown/hidden separately. The premium
+ // SMS subsection should only be visible if the app has tried to send to a premium SMS.
+ if (asp.getPermissionCount() > 0
+ || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
+ permsView.setVisibility(View.VISIBLE);
+ } else {
+ permsView.setVisibility(View.GONE);
+ }
+ // Premium SMS permission subsection
+ TextView securityBillingDesc = (TextView) permsView.findViewById(
+ R.id.security_settings_billing_desc);
+ LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
+ R.id.security_settings_billing_list);
+ if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
+ // Show the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.VISIBLE);
+ securityBillingList.setVisibility(View.VISIBLE);
+ Spinner spinner = (Spinner) permsView.findViewById(
+ R.id.security_settings_premium_sms_list);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
+ R.array.security_settings_premium_sms_values,
+ android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ // List items are in the same order as SmsUsageMonitor constants, offset by 1.
+ spinner.setSelection(premiumSmsPermission - 1);
+ spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
+ mPackageName, mSmsManager));
+ } else {
+ // Hide the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.GONE);
+ securityBillingList.setVisibility(View.GONE);
+ }
+ // App permissions subsection
+ if (asp.getPermissionCount() > 0) {
+ // Make the security sections header visible
+ LinearLayout securityList = (LinearLayout) permsView.findViewById(
+ R.id.security_settings_list);
+ securityList.removeAllViews();
+ securityList.addView(asp.getPermissionsViewWithRevokeButtons());
+ // If this app is running under a shared user ID with other apps,
+ // update the description to explain this.
+ String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
+ if (packages != null && packages.length > 1) {
+ ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
+ for (int i=0; i<packages.length; i++) {
+ String pkg = packages[i];
+ if (mPackageInfo.packageName.equals(pkg)) {
+ continue;
+ }
+ try {
+ ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
+ pnames.add(ainfo.loadLabel(mPm));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ final int N = pnames.size();
+ if (N > 0) {
+ final Resources res = getActivity().getResources();
+ String appListStr;
+ if (N == 1) {
+ appListStr = pnames.get(0).toString();
+ } else if (N == 2) {
+ appListStr = res.getString(R.string.join_two_items, pnames.get(0),
+ pnames.get(1));
+ } else {
+ appListStr = pnames.get(N-2).toString();
+ for (int i=N-3; i>=0; i--) {
+ appListStr = res.getString(i == 0 ? R.string.join_many_items_first
+ : R.string.join_many_items_middle, pnames.get(i), appListStr);
+ }
+ appListStr = res.getString(R.string.join_many_items_last,
+ appListStr, pnames.get(N-1));
+ }
+ TextView descr = (TextView) mRootView.findViewById(
+ R.id.security_settings_desc);
+ descr.setText(res.getString(R.string.security_settings_desc_multi,
+ mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
+ }
+ }
+ }
+ return true;
+ }
+
+ private int getPremiumSmsPermission(String packageName) {
+ try {
+ if (mSmsManager != null) {
+ return mSmsManager.getPremiumSmsPermission(packageName);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ // No dialogs for Permissions screen.
+ return null;
+ }
+
+ public static CharSequence getSummary(AppEntry appEntry, Context context) {
+ AppSecurityPermissions asp = new AppSecurityPermissions(context,
+ appEntry.info.packageName);
+ int count = asp.getPermissionCount();
+ return context.getResources().getQuantityString(R.plurals.permissions_summary,
+ count, count);
+ }
+
+ private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
+ private final String mPackageName;
+ private final ISms mSmsManager;
+
+ PremiumSmsSelectionListener(String packageName, ISms smsManager) {
+ mPackageName = packageName;
+ mSmsManager = smsManager;
+ }
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ if (position >= 0 && position < 3) {
+ if (localLOGV) Log.d(TAG, "Selected premium SMS policy " + position);
+ setPremiumSmsPermission(mPackageName, (position + 1));
+ } else {
+ Log.e(TAG, "Error: unknown premium SMS policy " + position);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Ignored
+ }
+
+ private void setPremiumSmsPermission(String packageName, int permission) {
+ try {
+ if (mSmsManager != null) {
+ mSmsManager.setPremiumSmsPermission(packageName, permission);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
new file mode 100644
index 0000000..3df01ed
--- /dev/null
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -0,0 +1,501 @@
+/*
+ * 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.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.applications.ApplicationsState.Callbacks;
+
+public class AppStorageSettings extends AppInfoWithHeader implements OnClickListener, Callbacks {
+ private static final String TAG = AppStorageSettings.class.getSimpleName();
+
+ //internal constants used in Handler
+ private static final int OP_SUCCESSFUL = 1;
+ private static final int OP_FAILED = 2;
+ private static final int MSG_CLEAR_USER_DATA = 1;
+ private static final int MSG_CLEAR_CACHE = 3;
+ private static final int MSG_PACKAGE_MOVE = 4;
+
+ // invalid size value used initially and also when size retrieval through PackageManager
+ // fails for whatever reason
+ private static final int SIZE_INVALID = -1;
+
+ // Result code identifiers
+ public static final int REQUEST_MANAGE_SPACE = 2;
+
+ private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
+ private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
+ private static final int DLG_MOVE_FAILED = DLG_BASE + 3;
+
+ private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
+ private TextView mTotalSize;
+ private TextView mAppSize;
+ private TextView mDataSize;
+ private TextView mExternalCodeSize;
+ private TextView mExternalDataSize;
+
+ // Views related to cache info
+ private TextView mCacheSize;
+ private Button mClearDataButton;
+ private Button mClearCacheButton;
+ private Button mMoveAppButton;
+ private boolean mMoveInProgress = false;
+
+ private boolean mCanClearData = true;
+ private boolean mHaveSizes = false;
+
+ private long mLastCodeSize = -1;
+ private long mLastDataSize = -1;
+ private long mLastExternalCodeSize = -1;
+ private long mLastExternalDataSize = -1;
+ private long mLastCacheSize = -1;
+ private long mLastTotalSize = -1;
+
+ private ClearCacheObserver mClearCacheObserver;
+ private ClearUserDataObserver mClearDataObserver;
+ private PackageMoveObserver mPackageMoveObserver;
+
+ // Resource strings
+ private CharSequence mInvalidSizeStr;
+ private CharSequence mComputingStr;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.storage_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup)view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+ mComputingStr = getActivity().getText(R.string.computing_size);
+ mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
+
+ // Set default values on sizes
+ mTotalSize = (TextView)view.findViewById(R.id.total_size_text);
+ mAppSize = (TextView)view.findViewById(R.id.application_size_text);
+ mDataSize = (TextView)view.findViewById(R.id.data_size_text);
+ mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text);
+ mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text);
+
+ if (Environment.isExternalStorageEmulated()) {
+ ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
+ ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
+ }
+
+ // Initialize clear data and move install location buttons
+ View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
+ mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
+
+ // Cache section
+ mCacheSize = (TextView)view.findViewById(R.id.cache_size_text);
+ mClearCacheButton = (Button)view.findViewById(R.id.clear_cache_button);
+ mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mClearCacheButton) {
+ // Lazy initialization of observer
+ if (mClearCacheObserver == null) {
+ mClearCacheObserver = new ClearCacheObserver();
+ }
+ mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
+ } else if(v == mClearDataButton) {
+ if (mAppEntry.info.manageSpaceActivityName != null) {
+ if (!Utils.isMonkeyRunning()) {
+ Intent intent = new Intent(Intent.ACTION_DEFAULT);
+ intent.setClassName(mAppEntry.info.packageName,
+ mAppEntry.info.manageSpaceActivityName);
+ startActivityForResult(intent, REQUEST_MANAGE_SPACE);
+ }
+ } else {
+ showDialogInner(DLG_CLEAR_DATA, 0);
+ }
+ } else if (v == mMoveAppButton) {
+ if (mPackageMoveObserver == null) {
+ mPackageMoveObserver = new PackageMoveObserver();
+ }
+ int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
+ PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
+ mMoveInProgress = true;
+ refreshButtons();
+ mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
+ }
+ }
+
+ private String getSizeStr(long size) {
+ if (size == SIZE_INVALID) {
+ return mInvalidSizeStr.toString();
+ }
+ return Formatter.formatFileSize(getActivity(), size);
+ }
+
+ private void refreshSizeInfo() {
+ if (mAppEntry.size == ApplicationsState.SIZE_INVALID
+ || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
+ mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
+ if (!mHaveSizes) {
+ mAppSize.setText(mComputingStr);
+ mDataSize.setText(mComputingStr);
+ mCacheSize.setText(mComputingStr);
+ mTotalSize.setText(mComputingStr);
+ }
+ mClearDataButton.setEnabled(false);
+ mClearCacheButton.setEnabled(false);
+
+ } else {
+ mHaveSizes = true;
+ long codeSize = mAppEntry.codeSize;
+ long dataSize = mAppEntry.dataSize;
+ if (Environment.isExternalStorageEmulated()) {
+ codeSize += mAppEntry.externalCodeSize;
+ dataSize += mAppEntry.externalDataSize;
+ } else {
+ if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
+ mLastExternalCodeSize = mAppEntry.externalCodeSize;
+ mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
+ }
+ if (mLastExternalDataSize != mAppEntry.externalDataSize) {
+ mLastExternalDataSize = mAppEntry.externalDataSize;
+ mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
+ }
+ }
+ if (mLastCodeSize != codeSize) {
+ mLastCodeSize = codeSize;
+ mAppSize.setText(getSizeStr(codeSize));
+ }
+ if (mLastDataSize != dataSize) {
+ mLastDataSize = dataSize;
+ mDataSize.setText(getSizeStr(dataSize));
+ }
+ long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
+ if (mLastCacheSize != cacheSize) {
+ mLastCacheSize = cacheSize;
+ mCacheSize.setText(getSizeStr(cacheSize));
+ }
+ if (mLastTotalSize != mAppEntry.size) {
+ mLastTotalSize = mAppEntry.size;
+ mTotalSize.setText(getSizeStr(mAppEntry.size));
+ }
+
+ if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
+ mClearDataButton.setEnabled(false);
+ } else {
+ mClearDataButton.setEnabled(true);
+ mClearDataButton.setOnClickListener(this);
+ }
+ if (cacheSize <= 0) {
+ mClearCacheButton.setEnabled(false);
+ } else {
+ mClearCacheButton.setEnabled(true);
+ mClearCacheButton.setOnClickListener(this);
+ }
+ }
+ if (mAppControlRestricted) {
+ mClearCacheButton.setEnabled(false);
+ mClearDataButton.setEnabled(false);
+ }
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ refreshButtons();
+ refreshSizeInfo();
+ return true;
+ }
+
+ private void refreshButtons() {
+ if (!mMoveInProgress) {
+ initMoveButton();
+ initDataButtons();
+ } else {
+ mMoveAppButton.setText(R.string.moving);
+ mMoveAppButton.setEnabled(false);
+ }
+ }
+
+ private void initDataButtons() {
+ // If the app doesn't have its own space management UI
+ // And it's a system app that doesn't allow clearing user data or is an active admin
+ // Then disable the Clear Data button.
+ if (mAppEntry.info.manageSpaceActivityName == null
+ && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
+ == ApplicationInfo.FLAG_SYSTEM
+ || mDpm.packageHasActiveAdmins(mPackageName))) {
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ mClearDataButton.setEnabled(false);
+ mCanClearData = false;
+ } else {
+ if (mAppEntry.info.manageSpaceActivityName != null) {
+ mClearDataButton.setText(R.string.manage_space_text);
+ } else {
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ }
+ mClearDataButton.setOnClickListener(this);
+ }
+
+ if (mAppControlRestricted) {
+ mClearDataButton.setEnabled(false);
+ }
+ }
+
+ private void initMoveButton() {
+ if (Environment.isExternalStorageEmulated()) {
+ mMoveAppButton.setVisibility(View.INVISIBLE);
+ return;
+ }
+ boolean dataOnly = (mPackageInfo == null) && (mAppEntry != null);
+ boolean moveDisable = true;
+ if (dataOnly) {
+ mMoveAppButton.setText(R.string.move_app);
+ } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ mMoveAppButton.setText(R.string.move_app_to_internal);
+ // Always let apps move to internal storage from sdcard.
+ moveDisable = false;
+ } else {
+ mMoveAppButton.setText(R.string.move_app_to_sdcard);
+ mCanBeOnSdCardChecker.init();
+ moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
+ }
+ if (moveDisable || mAppControlRestricted) {
+ mMoveAppButton.setEnabled(false);
+ } else {
+ mMoveAppButton.setOnClickListener(this);
+ mMoveAppButton.setEnabled(true);
+ }
+ }
+
+ /*
+ * Private method to initiate clearing user data when the user clicks the clear data
+ * button for a system package
+ */
+ private void initiateClearUserData() {
+ mClearDataButton.setEnabled(false);
+ // Invoke uninstall or clear user data based on sysPackage
+ String packageName = mAppEntry.info.packageName;
+ Log.i(TAG, "Clearing user data for package : " + packageName);
+ if (mClearDataObserver == null) {
+ mClearDataObserver = new ClearUserDataObserver();
+ }
+ ActivityManager am = (ActivityManager)
+ getActivity().getSystemService(Context.ACTIVITY_SERVICE);
+ boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
+ if (!res) {
+ // Clearing data failed for some obscure reason. Just log error for now
+ Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
+ showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
+ } else {
+ mClearDataButton.setText(R.string.recompute_size);
+ }
+ }
+
+ private void processMoveMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppEntry.info.packageName;
+ // Refresh the button attributes.
+ mMoveInProgress = false;
+ if (result == PackageManager.MOVE_SUCCEEDED) {
+ Log.i(TAG, "Moved resources for " + packageName);
+ // Refresh size information again.
+ mState.requestSize(mAppEntry.info.packageName);
+ } else {
+ showDialogInner(DLG_MOVE_FAILED, result);
+ }
+ refreshUi();
+ }
+
+ /*
+ * Private method to handle clear message notification from observer when
+ * the async operation from PackageManager is complete
+ */
+ private void processClearMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppEntry.info.packageName;
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ if(result == OP_SUCCESSFUL) {
+ Log.i(TAG, "Cleared user data for package : "+packageName);
+ mState.requestSize(mAppEntry.info.packageName);
+ } else {
+ mClearDataButton.setEnabled(true);
+ }
+ }
+
+ private CharSequence getMoveErrMsg(int errCode) {
+ switch (errCode) {
+ case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
+ return getActivity().getString(R.string.insufficient_storage);
+ case PackageManager.MOVE_FAILED_DOESNT_EXIST:
+ return getActivity().getString(R.string.does_not_exist);
+ case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
+ return getActivity().getString(R.string.app_forward_locked);
+ case PackageManager.MOVE_FAILED_INVALID_LOCATION:
+ return getActivity().getString(R.string.invalid_location);
+ case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
+ return getActivity().getString(R.string.system_package);
+ case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
+ return "";
+ }
+ return "";
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ switch (id) {
+ case DLG_CLEAR_DATA:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
+ .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ initiateClearUserData();
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_CANNOT_CLEAR_DATA:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
+ .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
+ .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mClearDataButton.setEnabled(false);
+ //force to recompute changed value
+ setIntentAndFinish(false, false);
+ }
+ })
+ .create();
+ case DLG_MOVE_FAILED:
+ CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
+ getMoveErrMsg(errorCode));
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
+ .setMessage(msg)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .create();
+ }
+ return null;
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ if (packageName.equals(mAppEntry.info.packageName)) {
+ refreshSizeInfo();
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (getView() == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_CLEAR_USER_DATA:
+ processClearMsg(msg);
+ break;
+ case MSG_CLEAR_CACHE:
+ // Refresh size info
+ mState.requestSize(mPackageName);
+ break;
+ case MSG_PACKAGE_MOVE:
+ processMoveMsg(msg);
+ break;
+ }
+ }
+ };
+
+ public static CharSequence getSummary(AppEntry appEntry, Context context) {
+ if (appEntry.size == ApplicationsState.SIZE_INVALID
+ || appEntry.size == ApplicationsState.SIZE_UNKNOWN) {
+ return context.getText(R.string.computing_size);
+ } else {
+ CharSequence storageType = context.getString(
+ (appEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0
+ ? R.string.storage_type_external
+ : R.string.storage_type_internal);
+ return context.getString(R.string.storage_summary_format,
+ getSize(appEntry, context), storageType);
+ }
+ }
+
+ private static CharSequence getSize(AppEntry appEntry, Context context) {
+ long size = appEntry.size;
+ if (size == SIZE_INVALID) {
+ return context.getText(R.string.invalid_size_value);
+ }
+ return Formatter.formatFileSize(context, size);
+ }
+
+ class ClearCacheObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(final String packageName, final boolean succeeded) {
+ final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
+ msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ class ClearUserDataObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(final String packageName, final boolean succeeded) {
+ final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
+ msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ class PackageMoveObserver extends IPackageMoveObserver.Stub {
+ public void packageMoved(String packageName, int returnCode) throws RemoteException {
+ final Message msg = mHandler.obtainMessage(MSG_PACKAGE_MOVE);
+ msg.arg1 = returnCode;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/applications/HeaderPreference.java b/src/com/android/settings/applications/HeaderPreference.java
new file mode 100644
index 0000000..a3d4bde
--- /dev/null
+++ b/src/com/android/settings/applications/HeaderPreference.java
@@ -0,0 +1,61 @@
+/*
+ * 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.res.TypedArray;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+
+public class HeaderPreference extends Preference {
+
+ private View mRootView;
+
+ public HeaderPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.Preference, 0, 0);
+ int layoutResource = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
+ 0);
+ if (layoutResource == 0) {
+ throw new IllegalArgumentException("HeaderPreference requires a layout to be defined");
+ }
+ // Need to create view now so that findViewById can be called immediately.
+ final View view = LayoutInflater.from(getContext())
+ .inflate(layoutResource, null, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+ mRootView = view;
+ }
+
+ @Override
+ protected View onCreateView(ViewGroup parent) {
+ return mRootView;
+ }
+
+ public View findViewById(int id) {
+ return mRootView.findViewById(id);
+ }
+
+}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 3aa948d..d77d63f 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -16,75 +16,47 @@
package com.android.settings.applications;
-import com.android.internal.telephony.ISms;
-import com.android.internal.telephony.SmsUsageMonitor;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.Utils;
-import com.android.settings.applications.ApplicationsState.AppEntry;
-
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.INotificationManager;
-import android.app.admin.DevicePolicyManager;
-import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
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.IPackageDataObserver;
-import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.hardware.usb.IUsbManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.text.SpannableString;
-import android.text.TextUtils;
-import android.text.format.Formatter;
-import android.text.style.BulletSpan;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import android.view.LayoutInflater;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AppSecurityPermissions;
-import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
import android.widget.TextView;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.notification.NotificationAppList;
+import com.android.settings.notification.NotificationAppList.AppRow;
+import com.android.settings.notification.NotificationAppList.Backend;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
/**
* Activity to display application information from Settings. This activity presents
* extended information associated with a package like code, data, total size, permissions
@@ -94,227 +66,48 @@ import android.widget.TextView;
* For non-system applications, there is no option to clear data. Instead there is an option to
* uninstall the application.
*/
-public class InstalledAppDetails extends Fragment
- implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
- ApplicationsState.Callbacks {
- private static final String TAG="InstalledAppDetails";
- private static final boolean localLOGV = false;
-
- public static final String ARG_PACKAGE_NAME = "package";
+public class InstalledAppDetails extends AppInfoBase
+ implements View.OnClickListener, OnPreferenceClickListener {
+
+ // Menu identifiers
+ public static final int UNINSTALL_ALL_USERS_MENU = 1;
+
+ // Result code identifiers
+ public static final int REQUEST_UNINSTALL = 0;
+ private static final int SUB_INFO_FRAGMENT = 1;
+
+ private static final int DLG_FORCE_STOP = DLG_BASE + 1;
+ private static final int DLG_DISABLE = DLG_BASE + 2;
+ private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
+ private static final int DLG_FACTORY_RESET = DLG_BASE + 4;
+
+ private static final String KEY_HEADER = "header_view";
+ private static final String KEY_NOTIFICATION = "notification_settings";
+ private static final String KEY_STORAGE = "storage_settings";
+ private static final String KEY_PERMISSION = "permission_settings";
+ private static final String KEY_DATA = "data_settings";
+ private static final String KEY_LAUNCH = "preferred_settings";
+
+ private final HashSet<String> mHomePackages = new HashSet<String>();
- private PackageManager mPm;
- private UserManager mUserManager;
- private IUsbManager mUsbManager;
- private AppWidgetManager mAppWidgetManager;
- private DevicePolicyManager mDpm;
- private ISms mSmsManager;
- private ApplicationsState mState;
- private ApplicationsState.Session mSession;
- private ApplicationsState.AppEntry mAppEntry;
private boolean mInitialized;
private boolean mShowUninstalled;
- private PackageInfo mPackageInfo;
- private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
- private View mRootView;
+ private HeaderPreference mHeader;
private Button mUninstallButton;
private View mMoreControlButtons;
private Button mSpecialDisableButton;
- private boolean mMoveInProgress = false;
private boolean mUpdatedSysApp = false;
- private Button mActivitiesButton;
- private View mScreenCompatSection;
- private CheckBox mAskCompatibilityCB;
- private CheckBox mEnableCompatibilityCB;
- private boolean mCanClearData = true;
- private boolean mAppControlRestricted = false;
private TextView mAppVersion;
- private TextView mTotalSize;
- private TextView mAppSize;
- private TextView mDataSize;
- private TextView mExternalCodeSize;
- private TextView mExternalDataSize;
- private ClearUserDataObserver mClearDataObserver;
- // Views related to cache info
- private TextView mCacheSize;
- private Button mClearCacheButton;
- private ClearCacheObserver mClearCacheObserver;
private Button mForceStopButton;
- private Button mClearDataButton;
- private Button mMoveAppButton;
- private CompoundButton mNotificationSwitch;
-
- private PackageMoveObserver mPackageMoveObserver;
-
- private final HashSet<String> mHomePackages = new HashSet<String>();
+ private Preference mNotificationPreference;
+ private Preference mStoragePreference;
+ private Preference mPermissionsPreference;
+ private Preference mLaunchPreference;
+ private Preference mDataPreference;
private boolean mDisableAfterUninstall;
-
- private boolean mHaveSizes = false;
- private long mLastCodeSize = -1;
- private long mLastDataSize = -1;
- private long mLastExternalCodeSize = -1;
- private long mLastExternalDataSize = -1;
- private long mLastCacheSize = -1;
- private long mLastTotalSize = -1;
-
- //internal constants used in Handler
- private static final int OP_SUCCESSFUL = 1;
- private static final int OP_FAILED = 2;
- private static final int CLEAR_USER_DATA = 1;
- private static final int CLEAR_CACHE = 3;
- private static final int PACKAGE_MOVE = 4;
-
- // invalid size value used initially and also when size retrieval through PackageManager
- // fails for whatever reason
- private static final int SIZE_INVALID = -1;
-
- // Resource strings
- private CharSequence mInvalidSizeStr;
- private CharSequence mComputingStr;
-
- // Dialog identifiers used in showDialog
- private static final int DLG_BASE = 0;
- private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
- private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
- private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
- private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
- private static final int DLG_FORCE_STOP = DLG_BASE + 5;
- private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
- private static final int DLG_DISABLE = DLG_BASE + 7;
- private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
- private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 9;
-
- // Menu identifiers
- public static final int UNINSTALL_ALL_USERS_MENU = 1;
-
- // Result code identifiers
- public static final int REQUEST_UNINSTALL = 1;
- public static final int REQUEST_MANAGE_SPACE = 2;
-
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // If the fragment is gone, don't process any more messages.
- if (getView() == null) {
- return;
- }
- switch (msg.what) {
- case CLEAR_USER_DATA:
- processClearMsg(msg);
- break;
- case CLEAR_CACHE:
- // Refresh size info
- mState.requestSize(mAppEntry.info.packageName);
- break;
- case PACKAGE_MOVE:
- processMoveMsg(msg);
- break;
- default:
- break;
- }
- }
- };
-
- class ClearUserDataObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- class ClearCacheObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
- msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- class PackageMoveObserver extends IPackageMoveObserver.Stub {
- public void packageMoved(String packageName, int returnCode) throws RemoteException {
- final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
- msg.arg1 = returnCode;
- mHandler.sendMessage(msg);
- }
- }
-
- private String getSizeStr(long size) {
- if (size == SIZE_INVALID) {
- return mInvalidSizeStr.toString();
- }
- return Formatter.formatFileSize(getActivity(), size);
- }
-
- private void initDataButtons() {
- // If the app doesn't have its own space management UI
- // And it's a system app that doesn't allow clearing user data or is an active admin
- // Then disable the Clear Data button.
- if (mAppEntry.info.manageSpaceActivityName == null
- && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
- == ApplicationInfo.FLAG_SYSTEM
- || mDpm.packageHasActiveAdmins(mPackageInfo.packageName))) {
- mClearDataButton.setText(R.string.clear_user_data_text);
- mClearDataButton.setEnabled(false);
- mCanClearData = false;
- } else {
- if (mAppEntry.info.manageSpaceActivityName != null) {
- mClearDataButton.setText(R.string.manage_space_text);
- } else {
- mClearDataButton.setText(R.string.clear_user_data_text);
- }
- mClearDataButton.setOnClickListener(this);
- }
-
- if (mAppControlRestricted) {
- mClearDataButton.setEnabled(false);
- }
- }
-
- private CharSequence getMoveErrMsg(int errCode) {
- switch (errCode) {
- case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
- return getActivity().getString(R.string.insufficient_storage);
- case PackageManager.MOVE_FAILED_DOESNT_EXIST:
- return getActivity().getString(R.string.does_not_exist);
- case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
- return getActivity().getString(R.string.app_forward_locked);
- case PackageManager.MOVE_FAILED_INVALID_LOCATION:
- return getActivity().getString(R.string.invalid_location);
- case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
- return getActivity().getString(R.string.system_package);
- case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
- return "";
- }
- return "";
- }
-
- private void initMoveButton() {
- if (Environment.isExternalStorageEmulated()) {
- mMoveAppButton.setVisibility(View.INVISIBLE);
- return;
- }
- boolean dataOnly = false;
- dataOnly = (mPackageInfo == null) && (mAppEntry != null);
- boolean moveDisable = true;
- if (dataOnly) {
- mMoveAppButton.setText(R.string.move_app);
- } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
- mMoveAppButton.setText(R.string.move_app_to_internal);
- // Always let apps move to internal storage from sdcard.
- moveDisable = false;
- } else {
- mMoveAppButton.setText(R.string.move_app_to_sdcard);
- mCanBeOnSdCardChecker.init();
- moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
- }
- if (moveDisable || mAppControlRestricted) {
- mMoveAppButton.setEnabled(false);
- } else {
- mMoveAppButton.setOnClickListener(this);
- mMoveAppButton.setEnabled(true);
- }
- }
+ // Used for updating notification preference.
+ private final Backend mBackend = new Backend();
private boolean handleDisableable(Button button) {
boolean disableable = false;
@@ -407,108 +200,48 @@ public class InstalledAppDetails extends Fragment
}
}
- private void initNotificationButton() {
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- boolean enabled = true; // default on
- try {
- enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName,
- mAppEntry.info.uid);
- } catch (android.os.RemoteException ex) {
- // this does not bode well
- }
- mNotificationSwitch.setChecked(enabled);
- if (Utils.isSystemPackage(mPm, mPackageInfo)) {
- mNotificationSwitch.setEnabled(false);
- } else if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
- // App is not installed on the current user
- mNotificationSwitch.setEnabled(false);
- } else {
- mNotificationSwitch.setEnabled(true);
- mNotificationSwitch.setOnCheckedChangeListener(this);
- }
- }
-
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mState = ApplicationsState.getInstance(getActivity().getApplication());
- mSession = mState.newSession(this);
- mPm = getActivity().getPackageManager();
- mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
- IBinder b = ServiceManager.getService(Context.USB_SERVICE);
- mUsbManager = IUsbManager.Stub.asInterface(b);
- mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
- mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
- mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-
- mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
-
- // Need to make sure we have loaded applications at this point.
- mSession.resume();
-
- retrieveAppEntry();
-
setHasOptionsMenu(true);
+ addPreferencesFromResource(R.xml.installed_app_details);
}
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final View view = inflater.inflate(R.layout.installed_app_details, container, false);
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ handleHeader();
- final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
- Utils.forceCustomPadding(allDetails, true /* additive padding */);
-
- mRootView = view;
- mComputingStr = getActivity().getText(R.string.computing_size);
-
- // Set default values on sizes
- mTotalSize = (TextView) view.findViewById(R.id.total_size_text);
- mAppSize = (TextView) view.findViewById(R.id.application_size_text);
- mDataSize = (TextView) view.findViewById(R.id.data_size_text);
- mExternalCodeSize = (TextView) view.findViewById(R.id.external_code_size_text);
- mExternalDataSize = (TextView) view.findViewById(R.id.external_data_size_text);
+ mNotificationPreference = findPreference(KEY_NOTIFICATION);
+ mNotificationPreference.setOnPreferenceClickListener(this);
+ mStoragePreference = findPreference(KEY_STORAGE);
+ mStoragePreference.setOnPreferenceClickListener(this);
+ mPermissionsPreference = findPreference(KEY_PERMISSION);
+ mPermissionsPreference.setOnPreferenceClickListener(this);
+ mLaunchPreference = findPreference(KEY_LAUNCH);
+ mLaunchPreference.setOnPreferenceClickListener(this);
+ mDataPreference = findPreference(KEY_DATA);
+ mDataPreference.setOnPreferenceClickListener(this);
+ // Data isn't ready, lets just pull it for now.
+ getPreferenceScreen().removePreference(mDataPreference);
+ }
- if (Environment.isExternalStorageEmulated()) {
- ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
- ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
- }
+ private void handleHeader() {
+ mHeader = (HeaderPreference) findPreference(KEY_HEADER);
// Get Control button panel
- View btnPanel = view.findViewById(R.id.control_buttons_panel);
- mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
+ View btnPanel = mHeader.findViewById(R.id.control_buttons_panel);
+ mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button);
mForceStopButton.setText(R.string.force_stop);
- mUninstallButton = (Button) btnPanel.findViewById(R.id.right_button);
+ mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button);
mForceStopButton.setEnabled(false);
-
+
// Get More Control button panel
- mMoreControlButtons = view.findViewById(R.id.more_control_buttons_panel);
- mMoreControlButtons.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
- mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.right_button);
+ mMoreControlButtons = mHeader.findViewById(R.id.more_control_buttons_panel);
+ mMoreControlButtons.findViewById(R.id.right_button).setVisibility(View.INVISIBLE);
+ mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.left_button);
mMoreControlButtons.setVisibility(View.GONE);
-
- // Initialize clear data and move install location buttons
- View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
- mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
- mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
-
- // Cache section
- mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
- mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
-
- mActivitiesButton = (Button) view.findViewById(R.id.clear_activities_button);
-
- // Screen compatibility control
- mScreenCompatSection = view.findViewById(R.id.screen_compatibility_section);
- mAskCompatibilityCB = (CheckBox) view.findViewById(R.id.ask_compatibility_cb);
- mEnableCompatibilityCB = (CheckBox) view.findViewById(R.id.enable_compatibility_cb);
-
- mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
-
- return view;
}
@Override
@@ -572,8 +305,9 @@ public class InstalledAppDetails extends Fragment
// Utility method to set application label and icon.
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
- final View appSnippet = mRootView.findViewById(R.id.app_snippet);
- appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0, appSnippet.getPaddingBottom());
+ final View appSnippet = mHeader.findViewById(R.id.app_snippet);
+ appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0,
+ appSnippet.getPaddingBottom());
ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
mState.ensureIcon(mAppEntry);
@@ -593,86 +327,6 @@ public class InstalledAppDetails extends Fragment
}
}
- @Override
- public void onResume() {
- super.onResume();
-
- mAppControlRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL);
- mSession.resume();
- if (!refreshUi()) {
- setIntentAndFinish(true, true);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mSession.pause();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- mSession.release();
- }
-
- @Override
- public void onAllSizesComputed() {
- }
-
- @Override
- public void onPackageIconChanged() {
- }
-
- @Override
- public void onPackageListChanged() {
- refreshUi();
- }
-
- @Override
- public void onRebuildComplete(ArrayList<AppEntry> apps) {
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
- if (packageName.equals(mAppEntry.info.packageName)) {
- refreshSizeInfo();
- }
- }
-
- @Override
- public void onRunningStateChanged(boolean running) {
- }
-
- private String retrieveAppEntry() {
- final Bundle args = getArguments();
- String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
- if (packageName == null) {
- Intent intent = (args == null) ?
- getActivity().getIntent() : (Intent) args.getParcelable("intent");
- if (intent != null) {
- packageName = intent.getData().getSchemeSpecificPart();
- }
- }
- mAppEntry = mState.getEntry(packageName);
- if (mAppEntry != null) {
- // Get application info again to refresh changed properties of application
- try {
- mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
- PackageManager.GET_DISABLED_COMPONENTS |
- PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
- }
- } else {
- Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
- mPackageInfo = null;
- }
-
- return packageName;
- }
-
private boolean signaturesMatch(String pkg1, String pkg2) {
if (pkg1 != null && pkg2 != null) {
try {
@@ -688,12 +342,9 @@ public class InstalledAppDetails extends Fragment
return false;
}
- private boolean refreshUi() {
- if (mMoveInProgress) {
- return true;
- }
- final String packageName = retrieveAppEntry();
-
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
if (mAppEntry == null) {
return false; // onCreate must have failed, make sure to exit
}
@@ -721,175 +372,18 @@ public class InstalledAppDetails extends Fragment
}
}
- // Get list of preferred activities
- List<ComponentName> prefActList = new ArrayList<ComponentName>();
-
- // Intent list cannot be null. so pass empty list
- List<IntentFilter> intentList = new ArrayList<IntentFilter>();
- mPm.getPreferredActivities(intentList, prefActList, packageName);
- if (localLOGV)
- Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
- boolean hasUsbDefaults = false;
- try {
- if (mUsbManager != null) {
- hasUsbDefaults = mUsbManager.hasDefaults(packageName, UserHandle.myUserId());
- }
- } catch (RemoteException e) {
- Log.e(TAG, "mUsbManager.hasDefaults", e);
- }
- boolean hasBindAppWidgetPermission =
- mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
-
- TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
- TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
- boolean autoLaunchEnabled = prefActList.size() > 0 || hasUsbDefaults;
- if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
- resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
- } else {
- boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
-
- if (hasBindAppWidgetPermission) {
- autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
- } else {
- autoLaunchTitleView.setText(R.string.auto_launch_label);
- }
-
- CharSequence text = null;
- int bulletIndent = getResources()
- .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
- if (autoLaunchEnabled) {
- CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
- SpannableString s = new SpannableString(autoLaunchEnableText);
- if (useBullets) {
- s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
- }
- text = (text == null) ?
- TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
- }
- if (hasBindAppWidgetPermission) {
- CharSequence alwaysAllowBindAppWidgetsText =
- getText(R.string.always_allow_bind_appwidgets_text);
- SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
- if (useBullets) {
- s.setSpan(new BulletSpan(bulletIndent),
- 0, alwaysAllowBindAppWidgetsText.length(), 0);
- }
- text = (text == null) ?
- TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
- }
- autoLaunchView.setText(text);
- mActivitiesButton.setEnabled(true);
- mActivitiesButton.setOnClickListener(this);
- }
-
- // Screen compatibility section.
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- int compatMode = am.getPackageScreenCompatMode(packageName);
- // For now these are always off; this is the old UI model which we
- // are no longer using.
- if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED
- || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) {
- mScreenCompatSection.setVisibility(View.VISIBLE);
- mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName));
- mAskCompatibilityCB.setOnCheckedChangeListener(this);
- mEnableCompatibilityCB.setChecked(compatMode == ActivityManager.COMPAT_MODE_ENABLED);
- mEnableCompatibilityCB.setOnCheckedChangeListener(this);
- } else {
- mScreenCompatSection.setVisibility(View.GONE);
- }
-
- // Security permissions section
- LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
- AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
- int premiumSmsPermission = getPremiumSmsPermission(packageName);
- // Premium SMS permission implies the app also has SEND_SMS permission, so the original
- // application permissions list doesn't have to be shown/hidden separately. The premium
- // SMS subsection should only be visible if the app has tried to send to a premium SMS.
- if (asp.getPermissionCount() > 0
- || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
- permsView.setVisibility(View.VISIBLE);
- } else {
- permsView.setVisibility(View.GONE);
- }
- // Premium SMS permission subsection
- TextView securityBillingDesc = (TextView) permsView.findViewById(
- R.id.security_settings_billing_desc);
- LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
- R.id.security_settings_billing_list);
- if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
- // Show the premium SMS permission selector
- securityBillingDesc.setVisibility(View.VISIBLE);
- securityBillingList.setVisibility(View.VISIBLE);
- Spinner spinner = (Spinner) permsView.findViewById(
- R.id.security_settings_premium_sms_list);
- ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
- R.array.security_settings_premium_sms_values,
- android.R.layout.simple_spinner_item);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
- // List items are in the same order as SmsUsageMonitor constants, offset by 1.
- spinner.setSelection(premiumSmsPermission - 1);
- spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
- packageName, mSmsManager));
- } else {
- // Hide the premium SMS permission selector
- securityBillingDesc.setVisibility(View.GONE);
- securityBillingList.setVisibility(View.GONE);
- }
- // App permissions subsection
- if (asp.getPermissionCount() > 0) {
- // Make the security sections header visible
- LinearLayout securityList = (LinearLayout) permsView.findViewById(
- R.id.security_settings_list);
- securityList.removeAllViews();
- securityList.addView(asp.getPermissionsViewWithRevokeButtons());
- // If this app is running under a shared user ID with other apps,
- // update the description to explain this.
- String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
- if (packages != null && packages.length > 1) {
- ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
- for (int i=0; i<packages.length; i++) {
- String pkg = packages[i];
- if (mPackageInfo.packageName.equals(pkg)) {
- continue;
- }
- try {
- ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
- pnames.add(ainfo.loadLabel(mPm));
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
- final int N = pnames.size();
- if (N > 0) {
- final Resources res = getActivity().getResources();
- String appListStr;
- if (N == 1) {
- appListStr = pnames.get(0).toString();
- } else if (N == 2) {
- appListStr = res.getString(R.string.join_two_items, pnames.get(0),
- pnames.get(1));
- } else {
- appListStr = pnames.get(N-2).toString();
- for (int i=N-3; i>=0; i--) {
- appListStr = res.getString(i == 0 ? R.string.join_many_items_first
- : R.string.join_many_items_middle, pnames.get(i), appListStr);
- }
- appListStr = res.getString(R.string.join_many_items_last,
- appListStr, pnames.get(N-1));
- }
- TextView descr = (TextView) mRootView.findViewById(
- R.id.security_settings_desc);
- descr.setText(res.getString(R.string.security_settings_desc_multi,
- mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
- }
- }
- }
-
checkForceStop();
setAppLabelAndIcon(mPackageInfo);
- refreshButtons();
- refreshSizeInfo();
+ initUninstallButtons();
+
+ // Update the preference summaries.
+ Activity context = getActivity();
+ mStoragePreference.setSummary(AppStorageSettings.getSummary(mAppEntry, context));
+ mPermissionsPreference.setSummary(AppPermissionSettings.getSummary(mAppEntry, context));
+ mLaunchPreference.setSummary(AppLaunchSettings.getSummary(mAppEntry, mUsbManager,
+ mPm, context));
+ mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
+ mBackend));
if (!mInitialized) {
// First time init: are we displaying an uninstalled app?
@@ -899,7 +393,7 @@ public class InstalledAppDetails extends Fragment
// All other times: if the app no longer exists then we want
// to go away.
try {
- ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo(
+ ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_DISABLED_COMPONENTS);
if (!mShowUninstalled) {
@@ -916,344 +410,63 @@ public class InstalledAppDetails extends Fragment
return true;
}
- private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
- private final String mPackageName;
- private final ISms mSmsManager;
-
- PremiumSmsSelectionListener(String packageName, ISms smsManager) {
- mPackageName = packageName;
- mSmsManager = smsManager;
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position,
- long id) {
- if (position >= 0 && position < 3) {
- Log.d(TAG, "Selected premium SMS policy " + position);
- setPremiumSmsPermission(mPackageName, (position + 1));
- } else {
- Log.e(TAG, "Error: unknown premium SMS policy " + position);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Ignored
- }
-
- private void setPremiumSmsPermission(String packageName, int permission) {
- try {
- if (mSmsManager != null) {
- mSmsManager.setPremiumSmsPermission(packageName, permission);
- }
- } catch (RemoteException ex) {
- // ignored
- }
- }
- }
-
- private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
- title.setText(R.string.auto_launch_label);
- autoLaunchView.setText(R.string.auto_launch_disable_text);
- // Disable clear activities button
- mActivitiesButton.setEnabled(false);
- }
-
- private void setIntentAndFinish(boolean finish, boolean appChanged) {
- if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
- Intent intent = new Intent();
- intent.putExtra(ManageApplications.APP_CHG, appChanged);
- SettingsActivity sa = (SettingsActivity)getActivity();
- sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
- }
-
- private void refreshSizeInfo() {
- if (mAppEntry.size == ApplicationsState.SIZE_INVALID
- || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
- mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
- if (!mHaveSizes) {
- mAppSize.setText(mComputingStr);
- mDataSize.setText(mComputingStr);
- mCacheSize.setText(mComputingStr);
- mTotalSize.setText(mComputingStr);
- }
- mClearDataButton.setEnabled(false);
- mClearCacheButton.setEnabled(false);
-
- } else {
- mHaveSizes = true;
- long codeSize = mAppEntry.codeSize;
- long dataSize = mAppEntry.dataSize;
- if (Environment.isExternalStorageEmulated()) {
- codeSize += mAppEntry.externalCodeSize;
- dataSize += mAppEntry.externalDataSize;
- } else {
- if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
- mLastExternalCodeSize = mAppEntry.externalCodeSize;
- mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
- }
- if (mLastExternalDataSize != mAppEntry.externalDataSize) {
- mLastExternalDataSize = mAppEntry.externalDataSize;
- mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
- }
- }
- if (mLastCodeSize != codeSize) {
- mLastCodeSize = codeSize;
- mAppSize.setText(getSizeStr(codeSize));
- }
- if (mLastDataSize != dataSize) {
- mLastDataSize = dataSize;
- mDataSize.setText(getSizeStr(dataSize));
- }
- long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
- if (mLastCacheSize != cacheSize) {
- mLastCacheSize = cacheSize;
- mCacheSize.setText(getSizeStr(cacheSize));
- }
- if (mLastTotalSize != mAppEntry.size) {
- mLastTotalSize = mAppEntry.size;
- mTotalSize.setText(getSizeStr(mAppEntry.size));
- }
-
- if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
- mClearDataButton.setEnabled(false);
- } else {
- mClearDataButton.setEnabled(true);
- mClearDataButton.setOnClickListener(this);
- }
- if (cacheSize <= 0) {
- mClearCacheButton.setEnabled(false);
- } else {
- mClearCacheButton.setEnabled(true);
- mClearCacheButton.setOnClickListener(this);
- }
- }
- if (mAppControlRestricted) {
- mClearCacheButton.setEnabled(false);
- mClearDataButton.setEnabled(false);
- }
- }
-
- /*
- * Private method to handle clear message notification from observer when
- * the async operation from PackageManager is complete
- */
- private void processClearMsg(Message msg) {
- int result = msg.arg1;
- String packageName = mAppEntry.info.packageName;
- mClearDataButton.setText(R.string.clear_user_data_text);
- if(result == OP_SUCCESSFUL) {
- Log.i(TAG, "Cleared user data for package : "+packageName);
- mState.requestSize(mAppEntry.info.packageName);
- } else {
- mClearDataButton.setEnabled(true);
- }
- checkForceStop();
- }
-
- private void refreshButtons() {
- if (!mMoveInProgress) {
- initUninstallButtons();
- initDataButtons();
- initMoveButton();
- initNotificationButton();
- } else {
- mMoveAppButton.setText(R.string.moving);
- mMoveAppButton.setEnabled(false);
- mUninstallButton.setEnabled(false);
- mSpecialDisableButton.setEnabled(false);
- }
- }
-
- private void processMoveMsg(Message msg) {
- int result = msg.arg1;
- String packageName = mAppEntry.info.packageName;
- // Refresh the button attributes.
- mMoveInProgress = false;
- if (result == PackageManager.MOVE_SUCCEEDED) {
- Log.i(TAG, "Moved resources for " + packageName);
- // Refresh size information again.
- mState.requestSize(mAppEntry.info.packageName);
- } else {
- showDialogInner(DLG_MOVE_FAILED, result);
- }
- refreshUi();
- }
-
- /*
- * Private method to initiate clearing user data when the user clicks the clear data
- * button for a system package
- */
- private void initiateClearUserData() {
- mClearDataButton.setEnabled(false);
- // Invoke uninstall or clear user data based on sysPackage
- String packageName = mAppEntry.info.packageName;
- Log.i(TAG, "Clearing user data for package : " + packageName);
- if (mClearDataObserver == null) {
- mClearDataObserver = new ClearUserDataObserver();
- }
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
- if (!res) {
- // Clearing data failed for some obscure reason. Just log error for now
- Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
- showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
- } else {
- mClearDataButton.setText(R.string.recompute_size);
- }
- }
-
- private void showDialogInner(int id, int moveErrorCode) {
- DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
- newFragment.setTargetFragment(this, 0);
- newFragment.show(getFragmentManager(), "dialog " + id);
- }
-
- public static class MyAlertDialogFragment extends DialogFragment {
-
- public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) {
- MyAlertDialogFragment frag = new MyAlertDialogFragment();
- Bundle args = new Bundle();
- args.putInt("id", id);
- args.putInt("moveError", moveErrorCode);
- frag.setArguments(args);
- return frag;
- }
-
- InstalledAppDetails getOwner() {
- return (InstalledAppDetails)getTargetFragment();
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- int id = getArguments().getInt("id");
- int moveErrorCode = getArguments().getInt("moveError");
- switch (id) {
- case DLG_CLEAR_DATA:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
- .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().initiateClearUserData();
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_FACTORY_RESET:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
- .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
- false, false);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_APP_NOT_FOUND:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_not_found_dlg_title))
- .setMessage(getActivity().getText(R.string.app_not_found_dlg_title))
- .setNeutralButton(getActivity().getText(R.string.dlg_ok),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //force to recompute changed value
- getOwner().setIntentAndFinish(true, true);
- }
- })
- .create();
- case DLG_CANNOT_CLEAR_DATA:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
- .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
- .setNeutralButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- getOwner().mClearDataButton.setEnabled(false);
- //force to recompute changed value
- getOwner().setIntentAndFinish(false, false);
- }
- })
- .create();
- case DLG_FORCE_STOP:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
- .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Force stop
- getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_MOVE_FAILED:
- CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
- getOwner().getMoveErrMsg(moveErrorCode));
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
- .setMessage(msg)
- .setNeutralButton(R.string.dlg_ok, null)
- .create();
- case DLG_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
- .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the app
- new DisableChanger(getOwner(), getOwner().mAppEntry.info,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
- .execute((Object)null);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_DISABLE_NOTIFICATIONS:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title))
- .setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the package's notifications
- getOwner().setNotificationsEnabled(false);
- }
- })
- .setNegativeButton(R.string.dlg_cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Re-enable the checkbox
- getOwner().mNotificationSwitch.setChecked(true);
- }
- })
- .create();
- case DLG_SPECIAL_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
- .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
- false, true);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- }
- throw new IllegalArgumentException("unknown id " + id);
- }
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ switch (id) {
+ case DLG_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Disable the app
+ new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
+ .execute((Object)null);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_SPECIAL_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ uninstallPkg(mAppEntry.info.packageName,
+ false, true);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_FORCE_STOP:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
+ .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Force stop
+ forceStopPackage(mAppEntry.info.packageName);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_FACTORY_RESET:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ uninstallPkg(mAppEntry.info.packageName,
+ false, false);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ }
+ return null;
}
private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
@@ -1277,13 +490,6 @@ public class InstalledAppDetails extends Fragment
checkForceStop();
}
- private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
- }
- };
-
private void updateForceStopButton(boolean enabled) {
if (mAppControlRestricted) {
mForceStopButton.setEnabled(false);
@@ -1292,7 +498,7 @@ public class InstalledAppDetails extends Fragment
mForceStopButton.setOnClickListener(InstalledAppDetails.this);
}
}
-
+
private void checkForceStop() {
if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
// User can't force stop device admin.
@@ -1312,47 +518,21 @@ public class InstalledAppDetails extends Fragment
}
}
- static class DisableChanger extends AsyncTask<Object, Object, Object> {
- final PackageManager mPm;
- final WeakReference<InstalledAppDetails> mActivity;
- final ApplicationInfo mInfo;
- final int mState;
+ private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, CharSequence title) {
+ // start new fragment to display extended information
+ Bundle args = new Bundle();
+ args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName);
- DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
- mPm = activity.mPm;
- mActivity = new WeakReference<InstalledAppDetails>(activity);
- mInfo = info;
- mState = state;
- }
-
- @Override
- protected Object doInBackground(Object... params) {
- mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
- return null;
- }
+ SettingsActivity sa = (SettingsActivity) getActivity();
+ sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
}
- private void setNotificationsEnabled(boolean enabled) {
- String packageName = mAppEntry.info.packageName;
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- try {
- final boolean enable = mNotificationSwitch.isChecked();
- nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
- } catch (android.os.RemoteException ex) {
- mNotificationSwitch.setChecked(!enabled); // revert
- }
- }
-
- private int getPremiumSmsPermission(String packageName) {
- try {
- if (mSmsManager != null) {
- return mSmsManager.getPremiumSmsPermission(packageName);
- }
- } catch (RemoteException ex) {
- // ignored
- }
- return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
+ private void startNotifications() {
+ // start new fragment to display extended information
+ getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mAppEntry.info.packageName)
+ .putExtra(Settings.EXTRA_APP_UID, mAppEntry.info.uid));
}
/*
@@ -1381,69 +561,77 @@ public class InstalledAppDetails extends Fragment
}
} else if(v == mSpecialDisableButton) {
showDialogInner(DLG_SPECIAL_DISABLE, 0);
- } else if(v == mActivitiesButton) {
- if (mUsbManager != null) {
- mPm.clearPackagePreferredActivities(packageName);
- try {
- mUsbManager.clearDefaults(packageName, UserHandle.myUserId());
- } catch (RemoteException e) {
- Log.e(TAG, "mUsbManager.clearDefaults", e);
- }
- mAppWidgetManager.setBindAppWidgetPermission(packageName, false);
- TextView autoLaunchTitleView =
- (TextView) mRootView.findViewById(R.id.auto_launch_title);
- TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
- resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
- }
- } else if(v == mClearDataButton) {
- if (mAppEntry.info.manageSpaceActivityName != null) {
- if (!Utils.isMonkeyRunning()) {
- Intent intent = new Intent(Intent.ACTION_DEFAULT);
- intent.setClassName(mAppEntry.info.packageName,
- mAppEntry.info.manageSpaceActivityName);
- startActivityForResult(intent, REQUEST_MANAGE_SPACE);
- }
- } else {
- showDialogInner(DLG_CLEAR_DATA, 0);
- }
- } else if (v == mClearCacheButton) {
- // Lazy initialization of observer
- if (mClearCacheObserver == null) {
- mClearCacheObserver = new ClearCacheObserver();
- }
- mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
} else if (v == mForceStopButton) {
showDialogInner(DLG_FORCE_STOP, 0);
//forceStopPackage(mAppInfo.packageName);
- } else if (v == mMoveAppButton) {
- if (mPackageMoveObserver == null) {
- mPackageMoveObserver = new PackageMoveObserver();
- }
- int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
- PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
- mMoveInProgress = true;
- refreshButtons();
- mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
}
}
@Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- String packageName = mAppEntry.info.packageName;
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- if (buttonView == mAskCompatibilityCB) {
- am.setPackageAskScreenCompat(packageName, isChecked);
- } else if (buttonView == mEnableCompatibilityCB) {
- am.setPackageScreenCompatMode(packageName, isChecked ?
- ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED);
- } else if (buttonView == mNotificationSwitch) {
- if (!isChecked) {
- showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0);
- } else {
- setNotificationsEnabled(true);
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mStoragePreference) {
+ startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle());
+ } else if (preference == mNotificationPreference) {
+ startNotifications();
+ } else if (preference == mPermissionsPreference) {
+ startAppInfoFragment(AppPermissionSettings.class, mPermissionsPreference.getTitle());
+ } else if (preference == mLaunchPreference) {
+ startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
+ } else if (preference == mDataPreference) {
+ // Not yet.
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) {
+ return getNotificationSummary(appEntry, context, new Backend());
+ }
+
+ public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
+ Backend backend) {
+ AppRow appRow = NotificationAppList.loadAppRow(context.getPackageManager(), appEntry.info,
+ backend);
+ if (appRow.banned) {
+ return context.getString(R.string.notifications_disabled);
+ } else if (appRow.priority) {
+ if (appRow.sensitive) {
+ return context.getString(R.string.notifications_priority_sensitive);
}
+ return context.getString(R.string.notifications_priority);
+ } else if (appRow.sensitive) {
+ return context.getString(R.string.notifications_sensitive);
+ }
+ return context.getString(R.string.notifications_enabled);
+ }
+
+ static class DisableChanger extends AsyncTask<Object, Object, Object> {
+ final PackageManager mPm;
+ final WeakReference<InstalledAppDetails> mActivity;
+ final ApplicationInfo mInfo;
+ final int mState;
+
+ DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
+ mPm = activity.mPm;
+ mActivity = new WeakReference<InstalledAppDetails>(activity);
+ mInfo = info;
+ mState = state;
+ }
+
+ @Override
+ protected Object doInBackground(Object... params) {
+ mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
+ return null;
}
}
+
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
+ }
+ };
}
+
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..0bb54b2 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;
@@ -107,7 +112,7 @@ public final class BluetoothDevicePreference extends Preference implements
*/
setTitle(mCachedDevice.getName());
- int summaryResId = getConnectionSummary();
+ int summaryResId = mCachedDevice.getConnectionSummary();
if (summaryResId != 0) {
setSummary(summaryResId);
} else {
@@ -227,60 +232,6 @@ public final class BluetoothDevicePreference extends Preference implements
}
}
- private int getConnectionSummary() {
- final CachedBluetoothDevice cachedDevice = mCachedDevice;
-
- boolean profileConnected = false; // at least one profile is connected
- boolean a2dpNotConnected = false; // A2DP is preferred but not connected
- boolean headsetNotConnected = false; // Headset is preferred but not connected
-
- for (LocalBluetoothProfile profile : cachedDevice.getProfiles()) {
- int connectionStatus = cachedDevice.getProfileConnectionState(profile);
-
- switch (connectionStatus) {
- case BluetoothProfile.STATE_CONNECTING:
- case BluetoothProfile.STATE_DISCONNECTING:
- return Utils.getConnectionStateSummary(connectionStatus);
-
- case BluetoothProfile.STATE_CONNECTED:
- profileConnected = true;
- break;
-
- case BluetoothProfile.STATE_DISCONNECTED:
- if (profile.isProfileReady()) {
- if (profile instanceof A2dpProfile) {
- a2dpNotConnected = true;
- } else if (profile instanceof HeadsetProfile) {
- headsetNotConnected = true;
- }
- }
- break;
- }
- }
-
- if (profileConnected) {
- if (a2dpNotConnected && headsetNotConnected) {
- return R.string.bluetooth_connected_no_headset_no_a2dp;
- } else if (a2dpNotConnected) {
- return R.string.bluetooth_connected_no_a2dp;
- } else if (headsetNotConnected) {
- return R.string.bluetooth_connected_no_headset;
- } else {
- return R.string.bluetooth_connected;
- }
- }
-
- switch (cachedDevice.getBondState()) {
- case BluetoothDevice.BOND_BONDING:
- return R.string.bluetooth_pairing;
-
- case BluetoothDevice.BOND_BONDED:
- case BluetoothDevice.BOND_NONE:
- default:
- return 0;
- }
- }
-
private int getBtClassDrawable() {
BluetoothClass btClass = mCachedDevice.getBtClass();
if (btClass != null) {
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..f07a9f2 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) {
@@ -211,4 +220,6 @@ public abstract class DeviceListPreferenceFragment extends
updateProgressUi(false);
}
}
+
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
}
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..020ca0c 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,57 @@ 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) { }
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
+
+ @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/fuelgauge/BatteryHistoryChart.java b/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
index 3312162..9ec0565 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
@@ -20,7 +20,6 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.DashPathEffect;
import android.os.BatteryManager;
-import android.provider.Settings;
import android.text.format.DateFormat;
import android.text.format.Formatter;
import android.util.Log;
@@ -667,8 +666,8 @@ public class BatteryHistoryChart extends View {
}
private boolean isDayFirst() {
- LocaleData d = LocaleData.get(mContext.getResources().getConfiguration().locale);
- String value = d.shortDateFormat4;
+ final String value = LocaleData.get(getResources().getConfiguration().locale)
+ .getDateFormat(java.text.DateFormat.SHORT);
return value.indexOf('M') > value.indexOf('d');
}
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 0eeefa9..67a8074 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -37,6 +37,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
@@ -74,30 +75,8 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
}
mCreated = true;
if (mAppRow == null) return;
- final View content = getActivity().findViewById(R.id.main_content);
- final ViewGroup contentParent = (ViewGroup) content.getParent();
- final View bar = getActivity().getLayoutInflater().inflate(R.layout.app_notification_header,
- contentParent, false);
-
- final ImageView appIcon = (ImageView) bar.findViewById(R.id.app_icon);
- appIcon.setImageDrawable(mAppRow.icon);
-
- final TextView appName = (TextView) bar.findViewById(R.id.app_name);
- appName.setText(mAppRow.label);
-
- final View appSettings = bar.findViewById(R.id.app_settings);
- if (mAppRow.settingsIntent == null) {
- appSettings.setVisibility(View.GONE);
- } else {
- appSettings.setClickable(true);
- appSettings.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mContext.startActivity(mAppRow.settingsIntent);
- }
- });
- }
- contentParent.addView(bar, 0);
+ AppHeader.createAppHeader(getActivity(), mAppRow.icon, mAppRow.label,
+ mAppRow.settingsIntent);
}
@Override
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/search/Index.java b/src/com/android/settings/search/Index.java
index 3957cf6..267c6c0 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -30,6 +30,7 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MergeCursor;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.SearchIndexableData;
@@ -448,7 +449,8 @@ public class Index {
final PackageManager pm = mContext.getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
- return ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0);
+ return ((packInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
@@ -500,7 +502,12 @@ public class Index {
}
private SQLiteDatabase getWritableDatabase() {
- return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+ try {
+ return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+ } catch (SQLiteException e) {
+ Log.e(LOG_TAG, "Cannot open writable database", e);
+ return null;
+ }
}
private static Uri buildUriForXmlResources(String authority) {
@@ -1171,6 +1178,10 @@ public class Index {
final boolean forceUpdate = params[0].forceUpdate;
final SQLiteDatabase database = getWritableDatabase();
+ if (database == null) {
+ Log.e(LOG_TAG, "Cannot update Index as I cannot get a writable database");
+ return null;
+ }
final String localeStr = Locale.getDefault().toString();
try {
@@ -1291,8 +1302,12 @@ public class Index {
values.put(IndexDatabaseHelper.SavedQueriesColums.TIME_STAMP, now);
final SQLiteDatabase database = getWritableDatabase();
+ if (database == null) {
+ Log.e(LOG_TAG, "Cannot save Search queries as I cannot get a writable database");
+ return -1L;
+ }
- long lastInsertedRowId = -1;
+ long lastInsertedRowId = -1L;
try {
// First, delete all saved queries that are the same
database.delete(Tables.TABLE_SAVED_QUERIES,
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index 4566662..e9234d7 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -139,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;
}
}
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 206ed95..53fdf1b 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,20 +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();
- }
-
private void applyUserAppsStates() {
final int userId = mUser.getIdentifier();
if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
@@ -368,7 +344,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
Log.d(TAG, "Installing " + packageName);
}
}
- if (info != null && (info.flags&ApplicationInfo.FLAG_HIDDEN) != 0
+ if (info != null && (info.privateFlags&ApplicationInfo.PRIVATE_FLAG_HIDDEN) != 0
&& (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
disableUiForPackage(packageName);
mIPm.setApplicationHiddenSettingAsUser(packageName, false, userId);
@@ -635,9 +611,10 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
private boolean isAppEnabledForUser(PackageInfo pi) {
if (pi == null) return false;
final int flags = pi.applicationInfo.flags;
+ final int privateFlags = pi.applicationInfo.privateFlags;
// Return true if it is installed and not hidden
return ((flags&ApplicationInfo.FLAG_INSTALLED) != 0
- && (flags&ApplicationInfo.FLAG_HIDDEN) == 0);
+ && (privateFlags&ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0);
}
private void populateApps() {
@@ -654,25 +631,18 @@ 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);
+ // Settings app should be available to restricted user
+ mSelectedPackages.put(packageName, true);
+ 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,
@@ -683,44 +653,42 @@ 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));
- }
+ p.setOrder(MAX_APP_RESTRICTIONS * (mAppList.getPreferenceCount() + 2));
mSelectedPackages.put(packageName, p.isChecked());
- mAppListChanged = true;
- i++;
+ mAppList.addPreference(p);
}
+ 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) {
@@ -729,6 +697,47 @@ 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);
+ mAppList.addPreference(p);
+ }
+
private String getKeyForPackage(String packageName) {
return PKG_PREFIX + packageName;
}
@@ -772,6 +781,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) {
@@ -822,13 +837,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;
}
}
@@ -850,14 +861,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());
}
@@ -979,9 +983,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..e54ea9f 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>() {
@@ -832,8 +872,7 @@ public class UserSettings extends SettingsPreferenceFragment
for (int userId : values[0]) {
Bitmap bitmap = mUserManager.getUserIcon(userId);
if (bitmap == null) {
- bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId,
- /* light= */ false));
+ bitmap = Utils.getDefaultUserIconAsBitmap(userId);
}
mUserIcons.append(userId, bitmap);
}
@@ -849,15 +888,13 @@ public class UserSettings extends SettingsPreferenceFragment
}
private void assignDefaultPhoto(UserInfo user) {
- Bitmap bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(user.id,
- /* light= */ false));
+ Bitmap bitmap = Utils.getDefaultUserIconAsBitmap(user.id);
mUserManager.setUserIcon(user.id, bitmap);
}
private Drawable getEncircledDefaultIcon() {
if (mDefaultIconDrawable == null) {
- mDefaultIconDrawable = encircle(UserIcons.convertToBitmap(
- UserIcons.getDefaultUserIcon(UserHandle.USER_NULL, /* light= */ false)));
+ mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL));
}
return mDefaultIconDrawable;
}
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..f68410a
--- /dev/null
+++ b/src/com/android/settings/wifi/AccessPointPreference.java
@@ -0,0 +1,165 @@
+/*
+ * 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.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.net.wifi.WifiConfiguration;
+import android.os.RemoteException;
+import android.os.UserHandle;
+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 {
+ int userId = UserHandle.getUserId(mConfig.creatorUid);
+ ApplicationInfo appInfo = null;
+ if (mConfig.creatorName.equals(systemName)) {
+ appInfo = getContext().getApplicationInfo();
+ } else {
+ try {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ appInfo = ipm.getApplicationInfo(mConfig.creatorName, 0 /* flags */, userId);
+ } catch (RemoteException rex) {
+ // use default app icon
+ }
+ }
+ if (appInfo != null) {
+ drawable = appInfo.loadIcon(pm);
+ drawable = pm.getUserBadgedIcon(drawable, new UserHandle(userId));
+ }
+ }
+
+ 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..5716bec 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;
@@ -79,7 +73,9 @@ public class WifiSettingsForSetupWizard extends WifiSettings {
final Intent intent = getActivity().getIntent();
if (intent.getBooleanExtra(EXTRA_SHOW_WIFI_REQUIRED_INFO, false)) {
- view.findViewById(R.id.wifi_required_info).setVisibility(View.VISIBLE);
+ final View requiredInfo =
+ inflater.inflate(R.layout.setup_wifi_required_info, list, false);
+ list.addHeaderView(requiredInfo, null, false);
}
return view;
@@ -98,15 +94,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 +114,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 +134,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 dbd8eec..85afb7c 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -17,14 +17,11 @@
package com.android.settings.wifi;
import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
import android.net.wifi.ScanResult;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.util.List;
import android.app.Activity;
@@ -301,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);
}
@@ -395,19 +393,22 @@ public class WifiStatusTest extends Activity {
}
private void httpClientTest() {
- HttpClient client = new DefaultHttpClient();
+ HttpURLConnection urlConnection = null;
try {
// TODO: Hardcoded for now, make it UI configurable
- HttpGet request = new HttpGet("http://www.google.com");
- HttpResponse response = client.execute(request);
- if (response.getStatusLine().getStatusCode() == 200) {
+ URL url = new URL("http://www.google.com");
+ urlConnection = (HttpURLConnection) url.openConnection();
+ if (urlConnection.getResponseCode() == 200) {
mHttpClientTestResult = "Pass";
} else {
- mHttpClientTestResult = "Fail: Code: " + String.valueOf(response);
+ mHttpClientTestResult = "Fail: Code: " + urlConnection.getResponseMessage();
}
- request.abort();
} catch (IOException e) {
mHttpClientTestResult = "Fail: IOException";
+ } finally {
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
}
}
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 {