Merge "Data Saver Mode phrasing tweaks." into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2db1223..2eb2760 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1295,6 +1295,7 @@
<activity android:name="MonitoringCertInfoActivity"
android:label="@string/ssl_ca_cert_dialog_title"
android:theme="@style/Transparent"
+ android:excludeFromRecents="true"
android:taskAffinity="">
<intent-filter android:priority="1">
<action android:name="com.android.settings.MONITORING_CERT_INFO" />
diff --git a/res/layout/dashboard_category.xml b/res/layout/dashboard_category.xml
index b3500b2..7019a9c 100644
--- a/res/layout/dashboard_category.xml
+++ b/res/layout/dashboard_category.xml
@@ -21,7 +21,8 @@
android:orientation="vertical"
android:paddingBottom="8dip"
android:background="@color/card_background"
- android:importantForAccessibility="noHideDescendants">
+ android:importantForAccessibility="noHideDescendants"
+ android:elevation="@dimen/dashboard_category_elevation" >
<TextView android:id="@android:id/title"
android:layout_width="match_parent"
diff --git a/res/layout/dashboard_tile.xml b/res/layout/dashboard_tile.xml
index 983e6ea..2f87909 100644
--- a/res/layout/dashboard_tile.xml
+++ b/res/layout/dashboard_tile.xml
@@ -21,7 +21,8 @@
android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true"
- android:background="@drawable/selectable_card" >
+ android:background="@drawable/selectable_card"
+ android:elevation="@dimen/dashboard_category_elevation" >
<ImageView
android:id="@android:id/icon"
diff --git a/res/layout/font_size_activity.xml b/res/layout/font_size_activity.xml
index 5a4aba6..aa3930c 100644
--- a/res/layout/font_size_activity.xml
+++ b/res/layout/font_size_activity.xml
@@ -63,7 +63,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_font_size_16dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
@@ -82,7 +82,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_font_size_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index c64b68e..834bba2 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -19,9 +19,11 @@
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent">
- <LinearLayout style="@style/info_layout">
+ <LinearLayout style="@style/info_layout"
+ android:descendantFocusability="beforeDescendants"
+ android:focusableInTouchMode="true">
<!-- IMEI -->
<LinearLayout style="@style/entry_layout">
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
index 4d3ab39..0141019 100644
--- a/res/layout/screen_zoom_activity.xml
+++ b/res/layout/screen_zoom_activity.xml
@@ -62,7 +62,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_remove_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
@@ -81,7 +81,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_add_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index 620b43f..6822e95 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -119,8 +119,7 @@
<LinearLayout android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
+ android:orientation="vertical">
<TextView style="@style/vpn_label" android:text="@string/vpn_username"/>
<EditText style="@style/vpn_value" android:id="@+id/username"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6b67409..ce0a4a6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3441,6 +3441,13 @@
If you turn off notifications for this app, you may miss important alerts and updates.
</string>
+ <!-- Manage applications, individual application info screen, section heading for information about the app installer [CHAR_LIMIT=25] -->
+ <string name="app_install_details_group_title">Store</string>
+ <!-- Manage applications, individual application info screen, title for the option which will trigger application info in it's installer [CHAR_LIMIT=25] -->
+ <string name="app_install_details_title">App details</string>
+ <!-- Manage applications, individual application info screen, summary for the option which will trigger application info in it's installer [CHAR_LIMIT=50] -->
+ <string name="app_install_details_summary">App installed from <xliff:g id="app_store">%1$s</xliff:g></string>
+
<!-- App Ops Settings --> <skip />
<!-- [CHAR LIMIT=NONE] App ops settings title, on main settings screen. If clicked, the user is taken to a settings screen for app operations -->
<string name="app_ops_settings">App ops</string>
@@ -5273,13 +5280,22 @@
<!-- Button to close the SSL CA cert warning dialog box, meaning the user is done reading. [CHAR LIMIT=NONE] -->
<string name="done_button">Done</string>
<!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_dialog_title">Network monitoring</string>
+ <plurals name="ssl_ca_cert_dialog_title">
+ <item quantity="one">Trust or remove certificate</item>
+ <item quantity="other">Trust or remove certificates</item>
+ </plurals>
<!-- Text of message to show to users whose administrator has installed a SSL CA Cert. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_info_message">This device is managed by:\n<xliff:g id="managing_domain">%s</xliff:g>\n\nYour administrator is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nFor more information, contact your administrator.</string>
+ <plurals name="ssl_ca_cert_info_message">
+ <item quantity="one"><xliff:g id="managing_domain">%s</xliff:g> has installed a certificate authority for your work profile, which may allow them to monitor work network activity, including emails, apps, and secure websites. You can choose to either trust or remove this certificate.\n\nFor more information about this certificate, contact your admin.</item>
+ <item quantity="other"><xliff:g id="managing_domain">%s</xliff:g> has installed certificate authorities for your work profile, which may allow them to monitor work network activity, including emails, apps, and secure websites. You can choose to either trust or remove these certificates.\n\nFor more information about these certificates, contact your admin.</item>
+ </plurals>
<!-- Text of warning to show to users that have a SSL CA Cert installed. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
<!-- Label on button that will take the user to the Trusted Credentials settings page. [CHAR LIMIT=NONE]-->
- <string name="ssl_ca_cert_settings_button">Check trusted credentials</string>
+ <plurals name="ssl_ca_cert_settings_button">
+ <item quantity="one">Check certificate</item>
+ <item quantity="other">Check certificates</item>
+ </plurals>
<!-- User settings -->
<skip/>
@@ -7334,6 +7350,10 @@
<string name="notification_log_details_default">default</string>
<!-- Notification log debug tool: the word 'none' -->
<string name="notification_log_details_none">none</string>
+ <!-- Notification log debug tool: missing ranking information -->
+ <string name="notification_log_details_ranking_null">Ranking object is missing.</string>
+ <!-- Notification log debug tool: the word 'none' -->
+ <string name="notification_log_details_ranking_none">Ranking object doesn\'t contain this key.</string>
<!-- [CHAR_LIMIT=60] Label for special access screen -->
<string name="special_access">Special access</string>
@@ -7375,4 +7395,7 @@
<!-- [CHAR LIMIT=25] Bluetooth is disabled. -->
<string name="bluetooth_disabled">Disabled</string>
+ <!-- [CHAR LIMIT=60] Name of dev option called demo mode -->
+ <string name="demo_mode">Demo mode</string>
+
</resources>
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index 7415464..e737ba8 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -91,6 +91,12 @@
android:key="ota_disable_automatic_update"
android:title="@string/ota_disable_automatic_update" />
+ <PreferenceScreen
+ android:key="demo_mode"
+ android:title="@string/demo_mode">
+ <intent android:action="com.android.settings.action.DEMO_MODE" />
+ </PreferenceScreen>
+
<PreferenceCategory android:key="debug_debugging_category"
android:title="@string/debug_debugging_category">
diff --git a/src/com/android/settings/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
index 16d0685..d71ba9b 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
@@ -95,6 +95,8 @@
private String getTitleFromOrganizationName(int userId) {
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
- return (dpm != null) ? dpm.getOrganizationNameForUser(userId) : null;
+ CharSequence organizationNameForUser = (dpm != null)
+ ? dpm.getOrganizationNameForUser(userId) : null;
+ return organizationNameForUser != null ? organizationNameForUser.toString() : null;
}
}
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1b37066..594cd38 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -799,6 +799,8 @@
// Asynchronously throw up the IME, since there are issues with requesting it to be shown
// immediately.
if (mLockPatternView == null && !mCooldown) {
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
mHandler.postDelayed(new Runnable() {
@Override public void run() {
imm.showSoftInputUnchecked(0, null);
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 364700b..ddee6aa 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -82,6 +82,9 @@
public static final String EXTRA_DEVICE_ADMIN_PACKAGE_NAME =
"android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
+ public static final String EXTRA_CALLED_FROM_SUPPORT_DIALOG =
+ "android.app.extra.CALLED_FROM_SUPPORT_DIALOG";
+
Handler mHandler;
DevicePolicyManager mDPM;
@@ -113,6 +116,8 @@
int mCurSysAppOpMode;
int mCurToastAppOpMode;
+ boolean mIsCalledFromSupportDialog = false;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -129,6 +134,8 @@
return;
}
+ mIsCalledFromSupportDialog = getIntent().getBooleanExtra(
+ EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
String action = getIntent().getAction();
ComponentName who = (ComponentName)getIntent().getParcelableExtra(
@@ -459,6 +466,18 @@
}
@Override
+ protected void onUserLeaveHint() {
+ super.onUserLeaveHint();
+ // In case this is triggered from support dialog, finish this activity once the user leaves
+ // so that this won't appear as a background next time support dialog is triggered. This
+ // is because the support dialog activity and this belong to the same task and we can't
+ // start this in new activity since we need to know the calling package in this activity.
+ if (mIsCalledFromSupportDialog) {
+ finish();
+ }
+ }
+
+ @Override
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_WARNING: {
@@ -539,7 +558,7 @@
mActionButton.setText(R.string.remove_device_admin);
}
}
- String supportMessage = mDPM.getLongSupportMessageForUser(
+ CharSequence supportMessage = mDPM.getLongSupportMessageForUser(
mDeviceAdmin.getComponent(), UserHandle.myUserId());
if (!TextUtils.isEmpty(supportMessage)) {
mSupportMessage.setText(supportMessage);
diff --git a/src/com/android/settings/MonitoringCertInfoActivity.java b/src/com/android/settings/MonitoringCertInfoActivity.java
index 9dd83f5..cfa8e6f 100644
--- a/src/com/android/settings/MonitoringCertInfoActivity.java
+++ b/src/com/android/settings/MonitoringCertInfoActivity.java
@@ -18,78 +18,65 @@
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.os.Bundle;
-import android.os.RemoteException;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
+import android.os.UserHandle;
+import android.provider.Settings;
/**
* Activity that shows a dialog explaining that a CA cert is allowing someone to monitor network
- * traffic.
+ * traffic. This activity should be launched for the user into which the CA cert is installed.
*/
-public class MonitoringCertInfoActivity extends Activity implements OnClickListener {
-
- private boolean hasDeviceOwner = false;
+public class MonitoringCertInfoActivity extends Activity implements OnClickListener,
+ OnDismissListener {
@Override
protected void onCreate(Bundle savedStates) {
super.onCreate(savedStates);
- DevicePolicyManager dpm =
- (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+ final int numberOfCertificates = getIntent().getIntExtra(
+ Settings.EXTRA_NUMBER_OF_CERTIFICATES, 1);
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.ssl_ca_cert_dialog_title);
+ builder.setTitle(getResources().getQuantityText(R.plurals.ssl_ca_cert_dialog_title,
+ numberOfCertificates));
builder.setCancelable(true);
- // TODO See b/25772443
- hasDeviceOwner = dpm.getDeviceOwnerComponentOnCallingUser() != null;
- int buttonLabel;
- if (hasDeviceOwner) {
- // Institutional case. Show informational message.
- String message = this.getResources().getString(R.string.ssl_ca_cert_info_message,
- dpm.getDeviceOwnerNameOnAnyUser());
- builder.setMessage(message);
- buttonLabel = R.string.done_button;
- } else {
+ builder.setPositiveButton(getResources().getQuantityText(
+ R.plurals.ssl_ca_cert_settings_button, numberOfCertificates) , this);
+ builder.setNeutralButton(R.string.cancel, null);
+ builder.setOnDismissListener(this);
+
+ if (dpm.getProfileOwner() != null) {
+ builder.setMessage(getResources().getQuantityString(R.plurals.ssl_ca_cert_info_message,
+ numberOfCertificates, dpm.getProfileOwnerName()));
+ } else if (dpm.getDeviceOwnerComponentOnCallingUser() != null) {
+ builder.setMessage(getResources().getQuantityString(R.plurals.ssl_ca_cert_info_message,
+ numberOfCertificates, dpm.getDeviceOwnerNameOnAnyUser()));
+ } else {
// Consumer case. Show scary warning.
builder.setIcon(android.R.drawable.stat_notify_error);
builder.setMessage(R.string.ssl_ca_cert_warning_message);
- buttonLabel = R.string.ssl_ca_cert_settings_button;
}
- builder.setPositiveButton(buttonLabel, this);
-
- final Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override public void onCancel(DialogInterface dialog) {
- finish();
- }
- });
-
- dialog.show();
+ builder.show();
}
@Override
public void onClick(DialogInterface dialog, int which) {
- if (hasDeviceOwner) {
- finish();
- } else {
- Intent intent =
- new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- finish();
- }
+ Intent intent = new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(TrustedCredentialsSettings.ARG_SHOW_NEW_FOR_USER, UserHandle.myUserId());
+ startActivity(intent);
+ finish();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialogInterface) {
+ finish();
}
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 4a1c887..031a1ae 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -302,7 +302,7 @@
case EVENT_SET_PREFERRED_TYPE_DONE:
ar= (AsyncResult) msg.obj;
if (ar.exception != null) {
- log("Set preferred network type success.");
+ log("Set preferred network type failed.");
}
break;
case EVENT_QUERY_SMSC_DONE:
@@ -404,7 +404,7 @@
oemInfoButton.setEnabled(false);
}
- mCellInfoRefreshRateIndex = CELL_INFO_LIST_RATE_DISABLED;
+ mCellInfoRefreshRateIndex = 0; //disabled
mPreferredNetworkTypeResult = mPreferredNetworkLabels.length - 1; //Unknown
//FIXME: Replace with TelephonyManager call
@@ -438,9 +438,14 @@
mPingHostnameV6.setText(mPingHostnameResultV6);
mHttpClientTest.setText(mHttpClientTestResult);
- //move these here so that the initial updates in create don't cause values to reset
cellInfoRefreshRateSpinner.setOnItemSelectedListener(mCellInfoRefreshRateHandler);
+ //set selection after registering listener to force update
+ cellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
+
+ //set selection before registering to prevent update
+ preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
+
radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
imsVoLteProvisionedSwitch.setOnCheckedChangeListener(mImsVoLteCheckedChangeListener);
@@ -457,6 +462,8 @@
| PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
+
+ smsc.clearFocus();
}
@Override
@@ -466,6 +473,7 @@
log("onPause: unregister phone & data intents");
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ phone.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
}
private void restoreFromBundle(Bundle b) {
@@ -485,8 +493,6 @@
mPreferredNetworkLabels.length - 1);
mCellInfoRefreshRateIndex = b.getInt("mCellInfoRefreshRateIndex", 0);
-
- cellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
}
@Override
@@ -496,7 +502,6 @@
outState.putString("mHttpClientTestResult", mHttpClientTestResult);
outState.putInt("mPreferredNetworkTypeResult", mPreferredNetworkTypeResult);
-
outState.putInt("mCellInfoRefreshRateIndex", mCellInfoRefreshRateIndex);
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index bcb677d..049660e 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -625,6 +625,10 @@
startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
} else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) {
+ if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ mProfileChallengeUserId)) {
+ return false;
+ }
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_USER_ID, mProfileChallengeUserId);
startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
@@ -746,8 +750,16 @@
final String key = preference.getKey();
final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
if (KEY_VISIBLE_PATTERN_PROFILE.equals(key)) {
+ if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ mProfileChallengeUserId)) {
+ return false;
+ }
lockPatternUtils.setVisiblePatternEnabled((Boolean) value, mProfileChallengeUserId);
} else if (KEY_UNIFICATION.equals(key)) {
+ if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ mProfileChallengeUserId)) {
+ return false;
+ }
if ((Boolean) value) {
final boolean compliantForDevice =
(mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileChallengeUserId)
@@ -1282,17 +1294,15 @@
}
}
)
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- parentFragment.updateUnificationPreference();
- dismiss();
- }
- }
- )
+ .setNegativeButton(R.string.cancel, null)
.create();
}
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ ((SecuritySettings) getParentFragment()).updateUnificationPreference();
+ }
}
}
diff --git a/src/com/android/settings/ShowAdminSupportDetailsDialog.java b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
index 2f2379a..fce669c 100644
--- a/src/com/android/settings/ShowAdminSupportDetailsDialog.java
+++ b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
@@ -155,6 +155,7 @@
intent.setClass(activity, DeviceAdminAdd.class);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
enforcedAdmin.component);
+ intent.putExtra(DeviceAdminAdd.EXTRA_CALLED_FROM_SUPPORT_DIALOG, true);
// DeviceAdminAdd class may need to run as managed profile.
activity.startActivityAsUser(intent,
new UserHandle(enforcedAdmin.userId));
diff --git a/src/com/android/settings/TrustedCredentialsDialogBuilder.java b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
new file mode 100644
index 0000000..22dc936
--- /dev/null
+++ b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2016 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.annotation.NonNull;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.DialogInterface;
+import android.net.http.SslCertificate;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+
+import com.android.settings.TrustedCredentialsSettings.CertHolder;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+class TrustedCredentialsDialogBuilder extends AlertDialog.Builder {
+ public interface DelegateInterface {
+ List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder);
+ void removeOrInstallCert(CertHolder certHolder);
+ }
+
+ private final DialogEventHandler mDialogEventHandler;
+
+ public TrustedCredentialsDialogBuilder(Activity activity, DelegateInterface delegate) {
+ super(activity);
+ mDialogEventHandler = new DialogEventHandler(activity, delegate);
+
+ initDefaultBuilderParams();
+ }
+
+ public TrustedCredentialsDialogBuilder setCertHolder(CertHolder certHolder) {
+ return setCertHolders(certHolder == null ? new CertHolder[0]
+ : new CertHolder[]{certHolder});
+ }
+
+ public TrustedCredentialsDialogBuilder setCertHolders(@NonNull CertHolder[] certHolders) {
+ mDialogEventHandler.setCertHolders(certHolders);
+ return this;
+ }
+
+ @Override
+ public AlertDialog create() {
+ AlertDialog dialog = super.create();
+ dialog.setOnShowListener(mDialogEventHandler);
+ mDialogEventHandler.setDialog(dialog);
+ return dialog;
+ }
+
+ private void initDefaultBuilderParams() {
+ setTitle(com.android.internal.R.string.ssl_certificate);
+ setView(mDialogEventHandler.mRootContainer);
+
+ // Enable buttons here. The actual labels and listeners are configured in nextOrDismiss
+ setPositiveButton(R.string.trusted_credentials_trust_label, null);
+ setNegativeButton(android.R.string.ok, null);
+ }
+
+ private static class DialogEventHandler implements DialogInterface.OnShowListener,
+ View.OnClickListener {
+ private static final long OUT_DURATION_MS = 300;
+ private static final long IN_DURATION_MS = 200;
+
+ private final Activity mActivity;
+ private final DevicePolicyManager mDpm;
+ private final UserManager mUserManager;
+ private final DelegateInterface mDelegate;
+ private final LinearLayout mRootContainer;
+
+ private int mCurrentCertIndex = -1;
+ private AlertDialog mDialog;
+ private Button mPositiveButton;
+ private Button mNegativeButton;
+ private boolean mNeedsApproval;
+ private CertHolder[] mCertHolders = new CertHolder[0];
+ private View mCurrentCertLayout = null;
+
+ public DialogEventHandler(Activity activity, DelegateInterface delegate) {
+ mActivity = activity;
+ mDpm = activity.getSystemService(DevicePolicyManager.class);
+ mUserManager = activity.getSystemService(UserManager.class);
+ mDelegate = delegate;
+
+ mRootContainer = new LinearLayout(mActivity);
+ mRootContainer.setOrientation(LinearLayout.VERTICAL);
+ }
+
+ public void setDialog(AlertDialog dialog) {
+ mDialog = dialog;
+ }
+
+ public void setCertHolders(CertHolder[] certHolder) {
+ mCertHolders = certHolder;
+ }
+
+ @Override
+ public void onShow(DialogInterface dialogInterface) {
+ // Config the display content only when the dialog is shown because the
+ // positive/negative buttons don't exist until the dialog is shown
+ nextOrDismiss();
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mPositiveButton) {
+ if (mNeedsApproval) {
+ onClickTrust();
+ } else {
+ onClickOk();
+ }
+ } else if (view == mNegativeButton) {
+ onClickRemove();
+ }
+ }
+
+ private void onClickOk() {
+ nextOrDismiss();
+ }
+
+ private void onClickTrust() {
+ CertHolder certHolder = getCurrentCertInfo();
+ mDpm.approveCaCert(certHolder.getAlias(), certHolder.getUserId(), true);
+ nextOrDismiss();
+ }
+
+ private void onClickRemove() {
+ final CertHolder certHolder = getCurrentCertInfo();
+ new AlertDialog.Builder(mActivity)
+ .setMessage(getButtonConfirmation(certHolder))
+ .setPositiveButton(android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ mDelegate.removeOrInstallCert(certHolder);
+ dialog.dismiss();
+ nextOrDismiss();
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .show();
+ }
+
+ private CertHolder getCurrentCertInfo() {
+ return mCurrentCertIndex < mCertHolders.length ? mCertHolders[mCurrentCertIndex] : null;
+ }
+
+ private void nextOrDismiss() {
+ mCurrentCertIndex++;
+ // find next non-null cert or dismiss
+ while (mCurrentCertIndex < mCertHolders.length && getCurrentCertInfo() == null) {
+ mCurrentCertIndex++;
+ }
+
+ if (mCurrentCertIndex >= mCertHolders.length) {
+ mDialog.dismiss();
+ return;
+ }
+
+ updateViewContainer();
+ updatePositiveButton();
+ updateNegativeButton();
+ }
+
+ private void updatePositiveButton() {
+ final CertHolder certHolder = getCurrentCertInfo();
+ mNeedsApproval = !certHolder.isSystemCert() &&
+ !mDpm.isCaCertApproved(certHolder.getAlias(), certHolder.getUserId());
+
+ // The ok button is optional. User can still dismiss the dialog by other means.
+ // Display it only when trust button is not displayed, because we want users to
+ // either remove or trust a CA cert when the cert is installed by DPC app.
+ CharSequence displayText = mActivity.getText(mNeedsApproval
+ ? R.string.trusted_credentials_trust_label
+ : android.R.string.ok);
+ mPositiveButton = updateButton(DialogInterface.BUTTON_POSITIVE, displayText);
+ }
+
+ private void updateNegativeButton() {
+ final CertHolder certHolder = getCurrentCertInfo();
+ final boolean showRemoveButton = !mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_CREDENTIALS,
+ new UserHandle(certHolder.getUserId()));
+ CharSequence displayText = mActivity.getText(getButtonLabel(certHolder));
+ mNegativeButton = updateButton(DialogInterface.BUTTON_NEGATIVE, displayText);
+ mNegativeButton.setVisibility(showRemoveButton ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * mDialog.setButton doesn't trigger text refresh since mDialog has been shown.
+ * It's invoked only in case mDialog is refreshed.
+ * setOnClickListener is invoked to avoid dismiss dialog onClick
+ */
+ private Button updateButton(int buttonType, CharSequence displayText) {
+ mDialog.setButton(buttonType, displayText, (DialogInterface.OnClickListener) null);
+ Button button = mDialog.getButton(buttonType);
+ button.setText(displayText);
+ button.setOnClickListener(this);
+ return button;
+ }
+
+
+ private void updateViewContainer() {
+ CertHolder certHolder = getCurrentCertInfo();
+ LinearLayout nextCertLayout = getCertLayout(certHolder);
+
+ // Displaying first cert doesn't require animation
+ if (mCurrentCertLayout == null) {
+ mCurrentCertLayout = nextCertLayout;
+ mRootContainer.addView(mCurrentCertLayout);
+ } else {
+ animateViewTransition(nextCertLayout);
+ }
+ }
+
+ private LinearLayout getCertLayout(final CertHolder certHolder) {
+ final ArrayList<View> views = new ArrayList<View>();
+ final ArrayList<String> titles = new ArrayList<String>();
+ List<X509Certificate> certificates = mDelegate.getX509CertsFromCertHolder(certHolder);
+ if (certificates != null) {
+ for (X509Certificate certificate : certificates) {
+ SslCertificate sslCert = new SslCertificate(certificate);
+ views.add(sslCert.inflateCertificateView(mActivity));
+ titles.add(sslCert.getIssuedTo().getCName());
+ }
+ }
+
+ ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mActivity,
+ android.R.layout.simple_spinner_item,
+ titles);
+ arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner spinner = new Spinner(mActivity);
+ spinner.setAdapter(arrayAdapter);
+ spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ for (int i = 0; i < views.size(); i++) {
+ views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ LinearLayout certLayout = new LinearLayout(mActivity);
+ certLayout.setOrientation(LinearLayout.VERTICAL);
+ certLayout.addView(spinner);
+ for (int i = 0; i < views.size(); ++i) {
+ View certificateView = views.get(i);
+ // Show first cert by default
+ certificateView.setVisibility(i == 0 ? View.VISIBLE : View.GONE);
+ certLayout.addView(certificateView);
+ }
+
+ return certLayout;
+ }
+
+ private static int getButtonConfirmation(CertHolder certHolder) {
+ return certHolder.isSystemCert() ? ( certHolder.isDeleted()
+ ? R.string.trusted_credentials_enable_confirmation
+ : R.string.trusted_credentials_disable_confirmation )
+ : R.string.trusted_credentials_remove_confirmation;
+ }
+
+ private static int getButtonLabel(CertHolder certHolder) {
+ return certHolder.isSystemCert() ? ( certHolder.isDeleted()
+ ? R.string.trusted_credentials_enable_label
+ : R.string.trusted_credentials_disable_label )
+ : R.string.trusted_credentials_remove_label;
+ }
+
+ /* Animation code */
+ private void animateViewTransition(final View nextCertView) {
+ animateOldContent(new Runnable() {
+ @Override
+ public void run() {
+ addAndAnimateNewContent(nextCertView);
+ }
+ });
+ }
+
+ private void animateOldContent(Runnable callback) {
+ // Fade out
+ mCurrentCertLayout.animate()
+ .alpha(0)
+ .setDuration(OUT_DURATION_MS)
+ .setInterpolator(AnimationUtils.loadInterpolator(mActivity,
+ android.R.interpolator.fast_out_linear_in))
+ .withEndAction(callback)
+ .start();
+ }
+
+ private void addAndAnimateNewContent(View nextCertLayout) {
+ mCurrentCertLayout = nextCertLayout;
+ mRootContainer.removeAllViews();
+ mRootContainer.addView(nextCertLayout);
+
+ mRootContainer.addOnLayoutChangeListener( new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mRootContainer.removeOnLayoutChangeListener(this);
+
+ // Animate slide in from the right
+ final int containerWidth = mRootContainer.getWidth();
+ mCurrentCertLayout.setTranslationX(containerWidth);
+ mCurrentCertLayout.animate()
+ .translationX(0)
+ .setInterpolator(AnimationUtils.loadInterpolator(mActivity,
+ android.R.interpolator.linear_out_slow_in))
+ .setDuration(IN_DURATION_MS)
+ .start();
+ }
+ });
+ }
+ }
+}
diff --git a/src/com/android/settings/TrustedCredentialsSettings.java b/src/com/android/settings/TrustedCredentialsSettings.java
index 5e0aea7..e371229 100644
--- a/src/com/android/settings/TrustedCredentialsSettings.java
+++ b/src/com/android/settings/TrustedCredentialsSettings.java
@@ -16,8 +16,7 @@
package com.android.settings;
-import android.app.AlertDialog;
-import android.app.Dialog;
+import android.annotation.UiThread;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -41,16 +40,11 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.BaseExpandableListAdapter;
-import android.widget.Button;
import android.widget.ExpandableListView;
-import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
-import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TabHost;
import android.widget.TextView;
@@ -67,12 +61,17 @@
import java.util.HashMap;
import java.util.List;
-public class TrustedCredentialsSettings extends OptionsMenuFragment {
+public class TrustedCredentialsSettings extends OptionsMenuFragment
+ implements TrustedCredentialsDialogBuilder.DelegateInterface {
+
+ public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
private static final String TAG = "TrustedCredentialsSettings";
private UserManager mUserManager;
private KeyguardManager mKeyguardManager;
+ private int mTrustAllCaUserId;
+
private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER";
@@ -135,30 +134,6 @@
}
throw new AssertionError();
}
- private int getButtonLabel(CertHolder certHolder) {
- switch (this) {
- case SYSTEM:
- if (certHolder.mDeleted) {
- return R.string.trusted_credentials_enable_label;
- }
- return R.string.trusted_credentials_disable_label;
- case USER:
- return R.string.trusted_credentials_remove_label;
- }
- throw new AssertionError();
- }
- private int getButtonConfirmation(CertHolder certHolder) {
- switch (this) {
- case SYSTEM:
- if (certHolder.mDeleted) {
- return R.string.trusted_credentials_enable_confirmation;
- }
- return R.string.trusted_credentials_disable_confirmation;
- case USER:
- return R.string.trusted_credentials_remove_confirmation;
- }
- throw new AssertionError();
- }
private void postOperationUpdate(boolean ok, CertHolder certHolder) {
if (ok) {
if (certHolder.mTab.mSwitch) {
@@ -213,6 +188,9 @@
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
mKeyguardManager = (KeyguardManager) getActivity()
.getSystemService(Context.KEYGUARD_SERVICE);
+ mTrustAllCaUserId = getActivity().getIntent().getIntExtra(ARG_SHOW_NEW_FOR_USER,
+ UserHandle.USER_NULL);
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -590,6 +568,37 @@
mList.setVisibility(View.VISIBLE);
mProgressBar.setProgress(0);
mAliasLoaders.remove(mTab);
+ showTrustAllCaDialogIfNeeded();
+ }
+
+ private boolean isUserTabAndTrustAllCertMode() {
+ return isTrustAllCaCertModeInProgress() && mTab == Tab.USER;
+ }
+
+ @UiThread
+ private void showTrustAllCaDialogIfNeeded() {
+ if (!isUserTabAndTrustAllCertMode()) {
+ return;
+ }
+ List<CertHolder> certHolders = mCertHoldersByUserId.get(mTrustAllCaUserId);
+ if (certHolders == null) {
+ return;
+ }
+
+ List<CertHolder> unapprovedUserCertHolders = new ArrayList<>();
+ final DevicePolicyManager dpm = mContext.getSystemService(
+ DevicePolicyManager.class);
+ for (CertHolder cert : certHolders) {
+ if (cert != null && !dpm.isCaCertApproved(cert.mAlias, mTrustAllCaUserId)) {
+ unapprovedUserCertHolders.add(cert);
+ }
+ }
+
+ if (unapprovedUserCertHolders.size() == 0) {
+ Log.w(TAG, "no cert is pending approval for user " + mTrustAllCaUserId);
+ return;
+ }
+ showTrustAllCaDialog(unapprovedUserCertHolders);
}
}
@@ -603,7 +612,7 @@
}
}
- private static class CertHolder implements Comparable<CertHolder> {
+ /* package */ static class CertHolder implements Comparable<CertHolder> {
public int mProfileId;
private final IKeyChainService mService;
private final TrustedCertificateAdapterCommons mAdapter;
@@ -679,6 +688,22 @@
@Override public int hashCode() {
return mAlias.hashCode();
}
+
+ public int getUserId() {
+ return mProfileId;
+ }
+
+ public String getAlias() {
+ return mAlias;
+ }
+
+ public boolean isSystemCert() {
+ return mTab == Tab.SYSTEM;
+ }
+
+ public boolean isDeleted() {
+ return mDeleted;
+ }
}
private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
@@ -716,91 +741,34 @@
private Switch mSwitch;
}
- private void showCertDialog(final CertHolder certHolder) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setTitle(com.android.internal.R.string.ssl_certificate);
-
- final DevicePolicyManager dpm = getActivity().getSystemService(DevicePolicyManager.class);
- final ArrayList<View> views = new ArrayList<View>();
- final ArrayList<String> titles = new ArrayList<String>();
- addCertChain(certHolder, views, titles);
-
- ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),
- android.R.layout.simple_spinner_item,
- titles);
- arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- Spinner spinner = new Spinner(getActivity());
- spinner.setAdapter(arrayAdapter);
- spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- for (int i = 0; i < views.size(); i++) {
- views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- LinearLayout container = new LinearLayout(getActivity());
- container.setOrientation(LinearLayout.VERTICAL);
- container.addView(spinner);
- for (int i = 0; i < views.size(); ++i) {
- View certificateView = views.get(i);
- if (i != 0) {
- certificateView.setVisibility(View.GONE);
- }
- container.addView(certificateView);
- }
- builder.setView(container);
-
- if (certHolder.mTab == Tab.USER &&
- !dpm.isCaCertApproved(certHolder.mAlias, certHolder.mProfileId)) {
- builder.setPositiveButton(R.string.trusted_credentials_trust_label,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dpm.approveCaCert(certHolder.mAlias, certHolder.mProfileId, true);
- }
- });
- } else {
- // The ok button is optional. Display it only when trust button is not displayed.
- // User can still dismiss the dialog by other means.
- builder.setPositiveButton(android.R.string.ok, null);
- }
-
- if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS,
- new UserHandle(certHolder.mProfileId))) {
- builder.setNegativeButton(certHolder.mTab.getButtonLabel(certHolder),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(final DialogInterface parentDialog, int i) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setMessage(certHolder.mTab.getButtonConfirmation(certHolder));
- builder.setPositiveButton(android.R.string.yes,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- new AliasOperation(certHolder).execute();
- dialog.dismiss();
- parentDialog.dismiss();
- }
- });
- builder.setNegativeButton(android.R.string.no, null);
- AlertDialog alert = builder.create();
- alert.show();
- }
- });
- }
-
- builder.show();
+ private boolean isTrustAllCaCertModeInProgress() {
+ return mTrustAllCaUserId != UserHandle.USER_NULL;
}
- private void addCertChain(final CertHolder certHolder,
- final ArrayList<View> views, final ArrayList<String> titles) {
+ private void showTrustAllCaDialog(List<CertHolder> unapprovedCertHolders) {
+ final CertHolder[] arr = unapprovedCertHolders.toArray(
+ new CertHolder[unapprovedCertHolders.size()]);
+ new TrustedCredentialsDialogBuilder(getActivity(), this)
+ .setCertHolders(arr)
+ .setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialogInterface) {
+ // Avoid starting dialog again after Activity restart.
+ getActivity().getIntent().removeExtra(ARG_SHOW_NEW_FOR_USER);
+ mTrustAllCaUserId = UserHandle.USER_NULL;
+ }
+ })
+ .show();
+ }
+ private void showCertDialog(final CertHolder certHolder) {
+ new TrustedCredentialsDialogBuilder(getActivity(), this)
+ .setCertHolder(certHolder)
+ .show();
+ }
+
+ @Override
+ public List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder) {
List<X509Certificate> certificates = null;
try {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
@@ -817,18 +785,13 @@
} catch (RemoteException ex) {
Log.e(TAG, "RemoteException while retrieving certificate chain for root "
+ certHolder.mAlias, ex);
- return;
}
- for (X509Certificate certificate : certificates) {
- addCertDetails(certificate, views, titles);
- }
+ return certificates;
}
- private void addCertDetails(X509Certificate certificate, final ArrayList<View> views,
- final ArrayList<String> titles) {
- SslCertificate sslCert = new SslCertificate(certificate);
- views.add(sslCert.inflateCertificateView(getActivity()));
- titles.add(sslCert.getIssuedTo().getCName());
+ @Override
+ public void removeOrInstallCert(CertHolder certHolder) {
+ new AliasOperation(certHolder).execute();
}
private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
@@ -854,8 +817,7 @@
}
} catch (CertificateEncodingException | SecurityException | IllegalStateException
| RemoteException e) {
- Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias,
- e);
+ Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
return false;
}
}
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 527194f..4dd203c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -87,6 +87,8 @@
import android.view.animation.AnimationUtils;
import android.widget.ListView;
import android.widget.TabWidget;
+
+import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.util.UserIcons;
import java.io.IOException;
@@ -1104,5 +1106,15 @@
return Settings.Global.getInt(context.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
+
+ public static boolean startQuiteModeDialogIfNecessary(Context context, UserManager um,
+ int userId) {
+ if (um.isQuietModeEnabled(UserHandle.of(userId))) {
+ final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId);
+ context.startActivity(intent);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index f91f7bf..035b504 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -424,7 +424,7 @@
private Intent resolveIntent(Intent i) {
ResolveInfo result = getContext().getPackageManager().resolveActivity(i, 0);
- return result != null ? new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ return result != null ? new Intent(i.getAction())
.setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
@@ -902,6 +902,26 @@
category.addPreference(pref);
}
}
+
+ final String installerPackageName =
+ getContext().getPackageManager().getInstallerPackageName(mPackageName);
+ if (installerPackageName != null) {
+ final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+ .setPackage(installerPackageName);
+ final Intent result = resolveIntent(intent);
+ if (result != null) {
+ result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+ PreferenceCategory category = new PreferenceCategory(getPrefContext());
+ category.setTitle(R.string.app_install_details_group_title);
+ screen.addPreference(category);
+ Preference pref = new Preference(getPrefContext());
+ pref.setTitle(R.string.app_install_details_title);
+ pref.setKey("app_info_store");
+ pref.setSummary(getString(R.string.app_install_details_summary, mAppEntry.label));
+ pref.setIntent(result);
+ category.addPreference(pref);
+ }
+ }
}
private boolean hasPermission(String permission) {
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index 929179a..e6fcbcb 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -77,7 +77,6 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setAnimationAllowed(true);
mLocalManager = Utils.getLocalBtManager(getActivity());
if (mLocalManager == null) {
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index 292244c..8b29273 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -85,6 +85,10 @@
setShowingAll(true);
}
+ public List<Tile> getSuggestions() {
+ return mSuggestions;
+ }
+
public void setSuggestions(SuggestionParser suggestionParser) {
mSuggestionParser = suggestionParser;
mSuggestions = suggestionParser.getSuggestions();
diff --git a/src/com/android/settings/dashboard/DashboardDecorator.java b/src/com/android/settings/dashboard/DashboardDecorator.java
index 2e7afaf..9bcf39d 100644
--- a/src/com/android/settings/dashboard/DashboardDecorator.java
+++ b/src/com/android/settings/dashboard/DashboardDecorator.java
@@ -21,7 +21,6 @@
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import com.android.settings.R;
@@ -41,8 +40,6 @@
@Override
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
final int childCount = parent.getChildCount();
- final int width = parent.getWidth();
- final int bottom = parent.getBottom();
for (int i = 1; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
@@ -56,7 +53,8 @@
}
int top = getChildTop(child);
- mDivider.setBounds(0, top, width, top + mDivider.getIntrinsicHeight());
+ mDivider.setBounds(child.getLeft(), top, child.getRight(),
+ top + mDivider.getIntrinsicHeight());
mDivider.draw(c);
}
}
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 04c45fd..66b3730 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -77,19 +77,19 @@
@Override
public void onCreate(Bundle savedInstanceState) {
+ long startTime = System.currentTimeMillis();
super.onCreate(savedInstanceState);
- long startTime = System.currentTimeMillis();
List<DashboardCategory> categories =
((SettingsActivity) getActivity()).getDashboardCategories();
mSummaryLoader = new SummaryLoader(getActivity(), categories);
setHasOptionsMenu(true);
- if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
- + " ms");
Context context = getContext();
mConditionManager = ConditionManager.get(context);
mSuggestionParser = new SuggestionParser(context,
context.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering);
+ if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ + " ms");
}
@Override
@@ -108,17 +108,22 @@
@Override
public void onResume() {
+ long startTime = System.currentTimeMillis();
super.onResume();
((SettingsDrawerActivity) getActivity()).addCategoryListener(this);
mSummaryLoader.setListening(true);
- for (Condition c : mConditionManager.getVisibleConditions()) {
- MetricsLogger.visible(getContext(), c.getMetricsConstant());
+ for (Condition c : mConditionManager.getConditions()) {
+ if (c.shouldShow()) {
+ MetricsLogger.visible(getContext(), c.getMetricsConstant());
+ }
}
- for (Tile suggestion : mSuggestionParser.getSuggestions()) {
+ for (Tile suggestion : mAdapter.getSuggestions()) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion));
}
+ if (DEBUG_TIMING) Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime)
+ + " ms");
}
@Override
@@ -127,10 +132,12 @@
((SettingsDrawerActivity) getActivity()).remCategoryListener(this);
mSummaryLoader.setListening(false);
- for (Condition c : mConditionManager.getVisibleConditions()) {
- MetricsLogger.hidden(getContext(), c.getMetricsConstant());
+ for (Condition c : mConditionManager.getConditions()) {
+ if (c.shouldShow()) {
+ MetricsLogger.hidden(getContext(), c.getMetricsConstant());
+ }
}
- for (Tile suggestion : mSuggestionParser.getSuggestions()) {
+ for (Tile suggestion : mAdapter.getSuggestions()) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION,
DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion));
}
@@ -138,12 +145,15 @@
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
+ long startTime = System.currentTimeMillis();
if (hasWindowFocus) {
mConditionManager.addListener(this);
mConditionManager.refreshAll();
} else {
mConditionManager.remListener(this);
}
+ if (DEBUG_TIMING) Log.d(TAG, "onWindowFocusChanged took "
+ + (System.currentTimeMillis() - startTime) + " ms");
}
@Override
@@ -161,6 +171,7 @@
@Override
public void onViewCreated(View view, Bundle bundle) {
+ long startTime = System.currentTimeMillis();
mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
mLayoutManager = new LinearLayoutManager(getContext());
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
@@ -174,10 +185,11 @@
mDashboard.addItemDecoration(new DashboardDecorator(getContext()));
mAdapter = new DashboardAdapter(getContext());
mAdapter.setConditions(mConditionManager.getConditions());
- mAdapter.setSuggestions(mSuggestionParser);
mDashboard.setAdapter(mAdapter);
mSummaryLoader.setAdapter(mAdapter);
ConditionAdapterUtils.addDismiss(mDashboard);
+ if (DEBUG_TIMING) Log.d(TAG, "onViewCreated took "
+ + (System.currentTimeMillis() - startTime) + " ms");
rebuildUI();
}
diff --git a/src/com/android/settings/dashboard/SummaryLoader.java b/src/com/android/settings/dashboard/SummaryLoader.java
index 86cffde..55d97df 100644
--- a/src/com/android/settings/dashboard/SummaryLoader.java
+++ b/src/com/android/settings/dashboard/SummaryLoader.java
@@ -17,11 +17,8 @@
import android.app.Activity;
import android.content.ComponentName;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
+import android.os.*;
+import android.os.Process;
import android.util.ArrayMap;
import android.util.Log;
import com.android.settings.SettingsActivity;
@@ -51,7 +48,7 @@
public SummaryLoader(Activity activity, List<DashboardCategory> categories) {
mHandler = new Handler();
- mWorkerThread = new HandlerThread("SummaryLoader");
+ mWorkerThread = new HandlerThread("SummaryLoader", Process.THREAD_PRIORITY_BACKGROUND);
mWorkerThread.start();
mWorker = new Worker(mWorkerThread.getLooper());
mActivity = activity;
diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java
index 4352f2d..1d48d5d 100644
--- a/src/com/android/settings/dashboard/conditional/Condition.java
+++ b/src/com/android/settings/dashboard/conditional/Condition.java
@@ -35,7 +35,8 @@
private boolean mIsActive;
private long mLastStateChange;
- public Condition(ConditionManager manager) {
+ // All conditions must live in this package.
+ Condition(ConditionManager manager) {
mManager = manager;
}
@@ -45,10 +46,15 @@
mLastStateChange = bundle.getLong(KEY_LAST_STATE);
}
- void saveState(PersistableBundle bundle) {
- bundle.putBoolean(KEY_SILENCE, mIsSilenced);
- bundle.putBoolean(KEY_ACTIVE, mIsActive);
- bundle.putLong(KEY_LAST_STATE, mLastStateChange);
+ boolean saveState(PersistableBundle bundle) {
+ if (mIsSilenced) {
+ bundle.putBoolean(KEY_SILENCE, mIsSilenced);
+ }
+ if (mIsActive) {
+ bundle.putBoolean(KEY_ACTIVE, mIsActive);
+ bundle.putLong(KEY_LAST_STATE, mLastStateChange);
+ }
+ return mIsSilenced || mIsActive;
}
protected void notifyChanged() {
diff --git a/src/com/android/settings/dashboard/conditional/ConditionManager.java b/src/com/android/settings/dashboard/conditional/ConditionManager.java
index cd044ac..24d5f09 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionManager.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionManager.java
@@ -38,10 +38,12 @@
private static final boolean DEBUG = true;
+ private static final String PKG = "com.android.settings.dashboard.conditional.";
+
private static final String FILE_NAME = "condition_state.xml";
- private static final String TAG_CONDITIONS = "conditions";
- private static final String TAG_CONDITION = "condition";
- private static final String ATTR_CLASS = "class";
+ private static final String TAG_CONDITIONS = "cs";
+ private static final String TAG_CONDITION = "c";
+ private static final String ATTR_CLASS = "cls";
private static ConditionManager sInstance;
@@ -80,6 +82,9 @@
if (TAG_CONDITION.equals(parser.getName())) {
int depth = parser.getDepth();
String clz = parser.getAttributeValue("", ATTR_CLASS);
+ if (!clz.startsWith(PKG)) {
+ clz = PKG + clz;
+ }
Condition condition = createCondition(Class.forName(clz));
PersistableBundle bundle = PersistableBundle.restoreFromXml(parser);
if (DEBUG) Log.d(TAG, "Reading " + clz + " -- " + bundle);
@@ -109,12 +114,14 @@
final int N = mConditions.size();
for (int i = 0; i < N; i++) {
- serializer.startTag("", TAG_CONDITION);
- serializer.attribute("", ATTR_CLASS, mConditions.get(i).getClass().getName());
PersistableBundle bundle = new PersistableBundle();
- mConditions.get(i).saveState(bundle);
- bundle.saveToXml(serializer);
- serializer.endTag("", TAG_CONDITION);
+ if (mConditions.get(i).saveState(bundle)) {
+ serializer.startTag("", TAG_CONDITION);
+ final String clz = mConditions.get(i).getClass().getSimpleName();
+ serializer.attribute("", ATTR_CLASS, clz);
+ bundle.saveToXml(serializer);
+ serializer.endTag("", TAG_CONDITION);
+ }
}
serializer.endTag("", TAG_CONDITIONS);
@@ -133,6 +140,7 @@
addIfMissing(CellularDataCondition.class);
addIfMissing(BackgroundDataCondition.class);
addIfMissing(WorkModeCondition.class);
+ Collections.sort(mConditions, CONDITION_COMPARATOR);
}
private void addIfMissing(Class<? extends Condition> clz) {
@@ -187,12 +195,12 @@
conditions.add(mConditions.get(i));
}
}
- Collections.sort(conditions, CONDITION_COMPARATOR);
return conditions;
}
public void notifyChanged(Condition condition) {
saveToXml();
+ Collections.sort(mConditions, CONDITION_COMPARATOR);
final int N = mListeners.size();
for (int i = 0; i < N; i++) {
mListeners.get(i).onConditionsChanged();
@@ -209,7 +217,7 @@
public static ConditionManager get(Context context) {
if (sInstance == null) {
- sInstance = new ConditionManager(context);
+ sInstance = new ConditionManager(context.getApplicationContext());
}
return sInstance;
}
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 11b100c..b3c8e03 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -20,6 +20,7 @@
import android.content.Loader;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.net.INetworkStatsSession;
import android.net.NetworkPolicy;
@@ -30,6 +31,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
@@ -42,8 +44,10 @@
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settingslib.AppItem;
+import com.android.settingslib.Utils;
import com.android.settingslib.net.ChartData;
import com.android.settingslib.net.ChartDataLoader;
+import com.android.settingslib.net.UidDetailProvider;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -123,15 +127,6 @@
addUid(mAppItem.uids.keyAt(i));
}
}
- if (mPackages.size() != 0) {
- PackageManager pm = getPackageManager();
- try {
- ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
- mIcon = info.loadIcon(pm);
- mLabel = info.loadLabel(pm);
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
addPreferencesFromResource(R.xml.app_data_usage);
mTotalUsage = findPreference(KEY_TOTAL_USAGE);
@@ -142,6 +137,15 @@
mCycleAdapter = new CycleAdapter(getContext(), mCycle, mCycleListener, false);
if (UserHandle.isApp(mAppItem.key)) {
+ if (mPackages.size() != 0) {
+ PackageManager pm = getPackageManager();
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
+ mIcon = info.loadIcon(pm);
+ mLabel = info.loadLabel(pm);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
mRestrictBackground = (SwitchPreference) findPreference(KEY_RESTRICT_BACKGROUND);
mRestrictBackground.setOnPreferenceChangeListener(this);
mUnrestrictedData = (SwitchPreference) findPreference(KEY_UNRESTRICTED_DATA);
@@ -176,6 +180,12 @@
removePreference(KEY_APP_LIST);
}
} else {
+ final int userId = UidDetailProvider.getUserIdForKey(mAppItem.key);
+ final UserManager um = UserManager.get(getActivity());
+ final UserInfo info = um.getUserInfo(userId);
+ final PackageManager pm = getPackageManager();
+ mIcon = Utils.getUserIcon(getActivity(), um, info);
+ mLabel = Utils.getUserLabel(getActivity(), info);
removePreference(KEY_UNRESTRICTED_DATA);
removePreference(KEY_APP_SETTINGS);
removePreference(KEY_RESTRICT_BACKGROUND);
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
index e12afbf..e8c8cdd 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ b/src/com/android/settings/datausage/DataSaverSummary.java
@@ -100,6 +100,9 @@
@Override
public void onExtraInfoUpdated() {
+ if (!isAdded()) {
+ return;
+ }
int count = 0;
final ArrayList<AppEntry> allApps = mSession.getAllApps();
final int N = allApps.size();
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
index e3771d3..c9014c0 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
@@ -28,6 +28,7 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
@@ -215,8 +216,8 @@
mEntry = entry;
mEntry.ensureLabel(getContext());
setTitle(entry.label);
- setChecked(((AppStateDataUsageBridge.DataUsageState) entry.extraInfo)
- .isDataSaverWhitelisted);
+ final DataUsageState state = (DataUsageState) entry.extraInfo;
+ setChecked(state != null && state.isDataSaverWhitelisted);
if (mEntry.icon != null) {
setIcon(mEntry.icon);
}
@@ -224,8 +225,8 @@
public void reuse() {
setTitle(mEntry.label);
- setChecked(((AppStateDataUsageBridge.DataUsageState) mEntry.extraInfo)
- .isDataSaverWhitelisted);
+ final DataUsageState state = (DataUsageState) mEntry.extraInfo;
+ setChecked(state != null && state.isDataSaverWhitelisted);
}
@Override
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index a19b5b8..5f5975d 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -725,11 +725,16 @@
public void onClick(DialogInterface dialog, int which) {
final PrivateVolumeSettings target = (PrivateVolumeSettings) getTargetFragment();
final PackageManager pm = context.getPackageManager();
- final List<PackageInfo> infos = pm.getInstalledPackages(0);
- final ClearCacheObserver observer = new ClearCacheObserver(
- target, infos.size());
- for (PackageInfo info : infos) {
- pm.deleteApplicationCacheFiles(info.packageName, observer);
+ final UserManager um = context.getSystemService(UserManager.class);
+
+ for (int userId : um.getProfileIdsWithDisabled(context.getUserId())) {
+ final List<PackageInfo> infos = pm.getInstalledPackagesAsUser(0, userId);
+ final ClearCacheObserver observer = new ClearCacheObserver(
+ target, infos.size());
+ for (PackageInfo info : infos) {
+ pm.deleteApplicationCacheFilesAsUser(info.packageName, userId,
+ observer);
+ }
}
}
});
diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java
index 9e2c5ff..3b83e48 100644
--- a/src/com/android/settings/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/fingerprint/FingerprintSettings.java
@@ -40,6 +40,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
@@ -808,7 +809,7 @@
}
}
- public static Preference getFingerprintPreferenceForUser(Context context, int userId) {
+ public static Preference getFingerprintPreferenceForUser(Context context, final int userId) {
FingerprintManager fpm = (FingerprintManager) context.getSystemService(
Context.FINGERPRINT_SERVICE);
if (fpm == null || !fpm.isHardwareDetected()) {
@@ -818,7 +819,6 @@
Preference fingerprintPreference = new Preference(context);
fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);
fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title);
- Intent intent = new Intent();
final List<Fingerprint> items = fpm.getEnrolledFingerprints(userId);
final int fingerprintCount = items != null ? items.size() : 0;
final String clazz;
@@ -832,9 +832,22 @@
R.string.security_settings_fingerprint_preference_summary_none);
clazz = FingerprintEnrollIntroduction.class.getName();
}
- intent.setClassName("com.android.settings", clazz);
- intent.putExtra(Intent.EXTRA_USER_ID, userId);
- fingerprintPreference.setIntent(intent);
+ fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ final Context context = preference.getContext();
+ final UserManager userManager = UserManager.get(context);
+ if (Utils.startQuiteModeDialogIfNecessary(context, userManager,
+ userId)) {
+ return false;
+ }
+ Intent intent = new Intent();
+ intent.setClassName("com.android.settings", clazz);
+ intent.putExtra(Intent.EXTRA_USER_ID, userId);
+ context.startActivity(intent);
+ return true;
+ }
+ });
return fingerprintPreference;
}
}
diff --git a/src/com/android/settings/notification/NotificationStation.java b/src/com/android/settings/notification/NotificationStation.java
index 75acdc3..3ae1b63 100644
--- a/src/com/android/settings/notification/NotificationStation.java
+++ b/src/com/android/settings/notification/NotificationStation.java
@@ -20,14 +20,12 @@
import android.app.INotificationManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.*;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -36,7 +34,6 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.RecyclerView;
-import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -62,6 +59,7 @@
private static final boolean DEBUG = false;
private static final boolean DUMP_EXTRAS = true;
private static final boolean DUMP_PARCEL = true;
+ private Handler mHandler;
private static class HistoricalNotificationInfo {
public String pkg;
@@ -90,32 +88,44 @@
private final NotificationListenerService mListener = new NotificationListenerService() {
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap ranking) {
- logd("onNotificationPosted: %s", sbn.getNotification());
- final Handler h = getListView().getHandler();
+ logd("onNotificationPosted: %s, with update for %d", sbn.getNotification(),
+ ranking == null ? 0 : ranking.getOrderedKeys().length);
mRanking = ranking;
- h.removeCallbacks(mRefreshListRunnable);
- h.postDelayed(mRefreshListRunnable, 100);
+ scheduleRefreshList();
}
@Override
public void onNotificationRemoved(StatusBarNotification notification, RankingMap ranking) {
- final Handler h = getListView().getHandler();
+ logd("onNotificationRankingUpdate with update for %d",
+ ranking == null ? 0 : ranking.getOrderedKeys().length);
mRanking = ranking;
- h.removeCallbacks(mRefreshListRunnable);
- h.postDelayed(mRefreshListRunnable, 100);
+ scheduleRefreshList();
}
@Override
public void onNotificationRankingUpdate(RankingMap ranking) {
+ logd("onNotificationRankingUpdate with update for %d",
+ ranking == null ? 0 : ranking.getOrderedKeys().length);
mRanking = ranking;
+ scheduleRefreshList();
}
@Override
public void onListenerConnected() {
mRanking = getCurrentRanking();
+ logd("onListenerConnected with update for %d",
+ mRanking == null ? 0 : mRanking.getOrderedKeys().length);
+ scheduleRefreshList();
}
};
+ private void scheduleRefreshList() {
+ if (mHandler != null) {
+ mHandler.removeCallbacks(mRefreshListRunnable);
+ mHandler.postDelayed(mRefreshListRunnable, 100);
+ }
+ }
+
private Context mContext;
private final Comparator<HistoricalNotificationInfo> mNotificationSorter
@@ -131,6 +141,7 @@
public void onAttach(Activity activity) {
logd("onAttach(%s)", activity.getClass().getSimpleName());
super.onAttach(activity);
+ mHandler = new Handler(activity.getMainLooper());
mContext = activity;
mPm = mContext.getPackageManager();
mNoMan = INotificationManager.Stub.asInterface(
@@ -138,6 +149,14 @@
}
@Override
+ public void onDetach() {
+ logd("onDetach()");
+ mHandler.removeCallbacks(mRefreshListRunnable);
+ mHandler = null;
+ super.onDetach();
+ }
+
+ @Override
public void onPause() {
try {
mListener.unregisterAsSystemService();
@@ -280,11 +299,11 @@
.append(bold(getString(R.string.notification_log_details_icon)))
.append(delim)
.append(n.getSmallIcon().toString());
- if (!TextUtils.isEmpty(n.getGroup())) {
+ if (sbn.isGroup()) {
sb.append("\n")
.append(bold(getString(R.string.notification_log_details_group)))
.append(delim)
- .append(n.getGroup());
+ .append(sbn.getGroupKey());
if (n.isGroupSummary()) {
sb.append(bold(
getString(R.string.notification_log_details_group_summary)));
@@ -328,18 +347,31 @@
.append(bold(getString(R.string.notification_log_details_priority)))
.append(delim)
.append(Notification.priorityToString(n.priority));
- if (mRanking != null && mRanking.getRanking(sbn.getKey(), rank)) {
- sb.append("\n")
- .append(bold(getString(
- R.string.notification_log_details_importance)))
- .append(delim)
- .append(Ranking.importanceToString(rank.getImportance()));
- if (rank.getImportanceExplanation() != null) {
+ if (resultset == active) {
+ // mRanking only applies to active notifications
+ if (mRanking != null && mRanking.getRanking(sbn.getKey(), rank)) {
sb.append("\n")
.append(bold(getString(
- R.string.notification_log_details_explanation)))
+ R.string.notification_log_details_importance)))
.append(delim)
- .append(rank.getImportanceExplanation());
+ .append(Ranking.importanceToString(rank.getImportance()));
+ if (rank.getImportanceExplanation() != null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_explanation)))
+ .append(delim)
+ .append(rank.getImportanceExplanation());
+ }
+ } else {
+ if (mRanking == null) {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_ranking_null)));
+ } else {
+ sb.append("\n")
+ .append(bold(getString(
+ R.string.notification_log_details_ranking_none)));
+ }
}
}
if (n.contentIntent != null) {
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index c8f7b88..0a48874 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -93,14 +93,15 @@
private static final int MAX_SPEECH_RATE = 600;
/**
- * Maximum speech pitch value. Pitch value varies from 50 to 500, where 100
- * is the value for normal pitch. The max pitch value is set to 500, based on
- * feedback from a few accessibility users. The range for pitch is not set in stone,
+ * Speech pitch value.
+ * TTS pitch value varies from 25 to 400, where 100 is the value
+ * for normal pitch. The max pitch value is set to 400, based on feedback from users
+ * and the GoogleTTS pitch variation range. The range for pitch is not set in stone
* and should be readjusted based on user need.
- *
* This value should be kept in sync with the max value set in tts_settings xml.
*/
- private static final int MAX_SPEECH_PITCH = 500;
+ private static final int MAX_SPEECH_PITCH = 400;
+ private static final int MIN_SPEECH_PITCH = 25;
private PreferenceCategory mEnginePreferenceCategory;
private SeekBarPreference mDefaultPitchPref;
@@ -264,9 +265,9 @@
mDefaultRatePref.setOnPreferenceChangeListener(this);
mDefaultRatePref.setMax(MAX_SPEECH_RATE);
- mDefaultPitchPref.setProgress(mDefaultPitch);
+ mDefaultPitchPref.setProgress(getPitchSeekBarProgressFromSpeechPitchValue(mDefaultPitch));
mDefaultPitchPref.setOnPreferenceChangeListener(this);
- mDefaultPitchPref.setMax(MAX_SPEECH_PITCH);
+ mDefaultPitchPref.setMax(getPitchSeekBarProgressFromSpeechPitchValue(MAX_SPEECH_PITCH));
mCurrentEngine = mTts.getCurrentEngine();
@@ -291,6 +292,24 @@
}
/**
+ * The minimum pitch value should be > 0 but the minimum value of a seekbar in android
+ * is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_PITCH value
+ * so that the minimum seekbar progress value is MIN_SPEECH_PITCH.
+ * PITCH_VALUE = MIN_SPEECH_PITCH + PITCH_SEEKBAR_PROGRESS
+ */
+ private int getSpeechPitchValueFromSeekBarProgress(int progress) {
+ return MIN_SPEECH_PITCH + progress;
+ }
+
+ /**
+ * Since we are appending the MIN_SPEECH_PITCH to the pitch seekbar progress, the pitch
+ * seekbar progress should be set to (pitchValue - MIN_SPEECH_PITCH).
+ */
+ private int getPitchSeekBarProgressFromSpeechPitchValue(int pitchValue) {
+ return pitchValue - MIN_SPEECH_PITCH;
+ }
+
+ /**
* Called when the TTS engine is initialized.
*/
public void onInitEngine(int status) {
@@ -484,9 +503,10 @@
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
- updateSpeechRate(((Integer) objValue).intValue());
+ updateSpeechRate((Integer) objValue);
} else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
- mDefaultPitch = ((Integer) objValue).intValue();
+ int progress = (Integer) objValue;
+ mDefaultPitch = getSpeechPitchValueFromSeekBarProgress(progress);
try {
android.provider.Settings.Secure.putInt(getContentResolver(),
TTS_DEFAULT_PITCH, mDefaultPitch);
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index a13e29d..92050e9 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -170,6 +170,9 @@
// Show type-specific fields.
changeType(mProfile.type);
+ // Hide 'save login' when we are editing.
+ mSaveLogin.setVisibility(View.GONE);
+
// Switch to advanced view immediately if any advanced options are on
if (!mProfile.searchDomains.isEmpty() || !mProfile.dnsServers.isEmpty() ||
!mProfile.routes.isEmpty()) {
@@ -188,9 +191,6 @@
} else {
setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
- // Not editing, just show username and password.
- mView.findViewById(R.id.login).setVisibility(View.VISIBLE);
-
// Create a button to connect the network.
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.vpn_connect), mListener);
@@ -259,6 +259,7 @@
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (compoundButton == mAlwaysOnVpn) {
updateSaveLoginStatus();
+ getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
}
}
@@ -318,6 +319,9 @@
if (!editing) {
return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
}
+ if (mAlwaysOnVpn.isChecked() && !getProfile().isValidLockdownProfile()) {
+ return false;
+ }
if (mName.getText().length() == 0 || mServer.getText().length() == 0 ||
!validateAddresses(mDnsServers.getText().toString(), false) ||
!validateAddresses(mRoutes.getText().toString(), true)) {
@@ -441,7 +445,8 @@
break;
}
- profile.saveLogin = mSaveLogin.isChecked();
+ final boolean hasLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
+ profile.saveLogin = mSaveLogin.isChecked() || (mEditing && hasLogin);
return profile;
}
}
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index fc49fd8..5e4a7d9 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -152,12 +152,9 @@
return;
}
- // Update only if lockdown vpn has been changed
- if (!VpnUtils.isVpnLockdown(profile.key)) {
- final ConnectivityManager conn = ConnectivityManager.from(getActivity());
- conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
- VpnUtils.setLockdownVpn(getContext(), profile.key);
- }
+ final ConnectivityManager conn = ConnectivityManager.from(getActivity());
+ conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
+ VpnUtils.setLockdownVpn(getContext(), profile.key);
} else {
// update only if lockdown vpn has been changed
if (VpnUtils.isVpnLockdown(profile.key)) {