Merge "Import translations. DO NOT MERGE" into nyc-mr1-dev
diff --git a/src/com/android/settings/CustomListPreference.java b/src/com/android/settings/CustomListPreference.java
index ae83013..e7c7600 100644
--- a/src/com/android/settings/CustomListPreference.java
+++ b/src/com/android/settings/CustomListPreference.java
@@ -18,8 +18,13 @@
 
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
 import android.os.Bundle;
 import android.support.v14.preference.ListPreferenceDialogFragment;
 import android.support.v7.preference.ListPreference;
@@ -50,6 +55,18 @@
         return true;
     }
 
+    /**
+     * Called when a user is about to choose the given value, to determine if we
+     * should show a confirmation dialog.
+     *
+     * @param value the value the user is about to choose
+     * @return the message to show in a confirmation dialog, or {@code null} to
+     *         not request confirmation
+     */
+    protected CharSequence getConfirmationMessage(String value) {
+        return null;
+    }
+
     protected void onDialogStateRestored(Dialog dialog, Bundle savedInstanceState) {
     }
 
@@ -82,9 +99,7 @@
                 builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        CustomListPreferenceDialogFragment.this.onClick(dialog,
-                                DialogInterface.BUTTON_POSITIVE);
-                        dialog.dismiss();
+                        onItemChosen();
                     }
                 });
             }
@@ -115,18 +130,11 @@
 
         protected DialogInterface.OnClickListener getOnItemClickListener() {
             return new DialogInterface.OnClickListener() {
+                @Override
                 public void onClick(DialogInterface dialog, int which) {
                     setClickedDialogEntryIndex(which);
-
-
                     if (getCustomizablePreference().isAutoClosePreference()) {
-                        /*
-                         * Clicking on an item simulates the positive button
-                         * click, and dismisses the dialog.
-                         */
-                        CustomListPreferenceDialogFragment.this.onClick(dialog,
-                                DialogInterface.BUTTON_POSITIVE);
-                        dialog.dismiss();
+                        onItemChosen();
                     }
                 }
             };
@@ -136,17 +144,74 @@
             mClickedDialogEntryIndex = which;
         }
 
+        private String getValue() {
+            final ListPreference preference = getCustomizablePreference();
+            if (mClickedDialogEntryIndex >= 0 && preference.getEntryValues() != null) {
+                return preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Called when user has made a concrete item choice, but we might need
+         * to make a quick detour to confirm that choice with a second dialog.
+         */
+        protected void onItemChosen() {
+            final CharSequence message = getCustomizablePreference()
+                    .getConfirmationMessage(getValue());
+            if (message != null) {
+                final Fragment f = new ConfirmDialogFragment();
+                final Bundle args = new Bundle();
+                args.putCharSequence(Intent.EXTRA_TEXT, message);
+                f.setArguments(args);
+                f.setTargetFragment(CustomListPreferenceDialogFragment.this, 0);
+                final FragmentTransaction ft = getFragmentManager().beginTransaction();
+                ft.add(f, getTag() + "-Confirm");
+                ft.commitAllowingStateLoss();
+            } else {
+                onItemConfirmed();
+            }
+        }
+
+        /**
+         * Called when user has made a concrete item choice and we've fully
+         * confirmed they want to move forward (if we took a detour above).
+         */
+        protected void onItemConfirmed() {
+            onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
+            getDialog().dismiss();
+        }
+
         @Override
         public void onDialogClosed(boolean positiveResult) {
             getCustomizablePreference().onDialogClosed(positiveResult);
             final ListPreference preference = getCustomizablePreference();
-            if (positiveResult && mClickedDialogEntryIndex >= 0 &&
-                    preference.getEntryValues() != null) {
-                String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+            final String value = getValue();
+            if (positiveResult && value != null) {
                 if (preference.callChangeListener(value)) {
                     preference.setValue(value);
                 }
             }
         }
     }
+
+    public static class ConfirmDialogFragment extends DialogFragment {
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            return new AlertDialog.Builder(getActivity())
+                    .setMessage(getArguments().getCharSequence(Intent.EXTRA_TEXT))
+                    .setPositiveButton(android.R.string.ok, new OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            final Fragment f = getTargetFragment();
+                            if (f != null) {
+                                ((CustomListPreferenceDialogFragment) f).onItemConfirmed();
+                            }
+                        }
+                    })
+                    .setNegativeButton(android.R.string.cancel, null)
+                    .create();
+        }
+    }
 }
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 90dd9e0..0725386 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1150,5 +1150,14 @@
         }
         return false;
     }
-}
 
+    public static boolean isPackageDirectBootAware(Context context, String packageName) {
+        try {
+            final ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
+                    packageName, 0);
+            return ai.isDirectBootAware() || ai.isPartiallyDirectBootAware();
+        } catch (NameNotFoundException ignored) {
+        }
+        return false;
+    }
+}
diff --git a/src/com/android/settings/applications/DefaultEmergencyPreference.java b/src/com/android/settings/applications/DefaultEmergencyPreference.java
index f0a97b1..dd4dc2e 100644
--- a/src/com/android/settings/applications/DefaultEmergencyPreference.java
+++ b/src/com/android/settings/applications/DefaultEmergencyPreference.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.applications;
 
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,9 +29,11 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.AttributeSet;
-import com.android.internal.telephony.SmsApplication;
+
 import com.android.settings.AppListPreference;
+import com.android.settings.R;
 import com.android.settings.SelfAvailablePreference;
+import com.android.settings.Utils;
 
 import java.util.List;
 import java.util.Objects;
@@ -57,6 +58,12 @@
     }
 
     @Override
+    protected CharSequence getConfirmationMessage(String value) {
+        return Utils.isPackageDirectBootAware(getContext(), value) ? null
+                : getContext().getText(R.string.direct_boot_unaware_dialog_message);
+    }
+
+    @Override
     protected boolean persistString(String value) {
         String previousValue = Settings.Secure.getString(mContentResolver,
                 Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
diff --git a/src/com/android/settings/applications/DefaultPhonePreference.java b/src/com/android/settings/applications/DefaultPhonePreference.java
index fdaf7ad..5689c83 100644
--- a/src/com/android/settings/applications/DefaultPhonePreference.java
+++ b/src/com/android/settings/applications/DefaultPhonePreference.java
@@ -24,23 +24,28 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+
 import com.android.settings.AppListPreference;
+import com.android.settings.R;
 import com.android.settings.SelfAvailablePreference;
+import com.android.settings.Utils;
 
 import java.util.List;
 import java.util.Objects;
 
 public class DefaultPhonePreference extends AppListPreference implements SelfAvailablePreference {
-    private final Context mContext;
-
     public DefaultPhonePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mContext = context.getApplicationContext();
         loadDialerApps();
     }
 
     @Override
+    protected CharSequence getConfirmationMessage(String value) {
+        return Utils.isPackageDirectBootAware(getContext(), value) ? null
+                : getContext().getText(R.string.direct_boot_unaware_dialog_message);
+    }
+
+    @Override
     protected boolean persistString(String value) {
         if (!TextUtils.isEmpty(value) && !Objects.equals(value, getDefaultPackage())) {
             DefaultDialerManager.setDefaultDialerApplication(getContext(), value, mUserId);
diff --git a/src/com/android/settings/applications/DefaultSmsPreference.java b/src/com/android/settings/applications/DefaultSmsPreference.java
index 9315102..96ac9a2 100644
--- a/src/com/android/settings/applications/DefaultSmsPreference.java
+++ b/src/com/android/settings/applications/DefaultSmsPreference.java
@@ -22,19 +22,20 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+
 import com.android.internal.telephony.SmsApplication;
 import com.android.internal.telephony.SmsApplication.SmsApplicationData;
 import com.android.settings.AppListPreference;
+import com.android.settings.R;
 import com.android.settings.SelfAvailablePreference;
+import com.android.settings.Utils;
 
 import java.util.Collection;
 import java.util.Objects;
 
 public class DefaultSmsPreference extends AppListPreference implements SelfAvailablePreference {
-
     public DefaultSmsPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-
         loadSmsApps();
     }
 
@@ -60,6 +61,12 @@
     }
 
     @Override
+    protected CharSequence getConfirmationMessage(String value) {
+        return Utils.isPackageDirectBootAware(getContext(), value) ? null
+                : getContext().getText(R.string.direct_boot_unaware_dialog_message);
+    }
+
+    @Override
     protected boolean persistString(String value) {
         if (!TextUtils.isEmpty(value) && !Objects.equals(value, getDefaultPackage())) {
             SmsApplication.setDefaultApplication(value, getContext());
diff --git a/src/com/android/settings/dashboard/SupportItemAdapter.java b/src/com/android/settings/dashboard/SupportItemAdapter.java
index c5ff2a6..4ee28c6 100644
--- a/src/com/android/settings/dashboard/SupportItemAdapter.java
+++ b/src/com/android/settings/dashboard/SupportItemAdapter.java
@@ -23,6 +23,7 @@
 import android.app.DialogFragment;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
@@ -136,7 +137,8 @@
     public void onItemClicked(int position) {
         if (position >= 0 && position < mSupportData.size()) {
             final SupportData data = mSupportData.get(position);
-            if (data.intent != null) {
+            if (data.intent != null &&
+                    mActivity.getPackageManager().resolveActivity(data.intent, 0) != null) {
                 if (data.metricsEvent >= 0) {
                     MetricsLogger.action(mActivity, data.metricsEvent);
                 }
@@ -283,18 +285,25 @@
 
     private void addMoreHelpItems() {
         mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE_SPACER).build());
-        mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
-                .setIcon(R.drawable.ic_help_24dp)
-                .setTileTitle(R.string.support_help_feedback_title)
-                .setIntent(mSupportFeatureProvider.getHelpIntent(mActivity))
-                .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_HELP_AND_FEEDBACK)
-                .build());
-        mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
-                .setIcon(R.drawable.ic_lightbulb_outline_24)
-                .setTileTitle(R.string.support_tips_and_tricks_title)
-                .setIntent(mSupportFeatureProvider.getTipsAndTricksIntent(mActivity))
-                .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_TIPS_AND_TRICKS)
-                .build());
+        PackageManager packageManager = mActivity.getPackageManager();
+        Intent intent = mSupportFeatureProvider.getHelpIntent(mActivity);
+        if (packageManager.resolveActivity(intent, 0) != null) {
+            mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
+                    .setIcon(R.drawable.ic_help_24dp)
+                    .setTileTitle(R.string.support_help_feedback_title)
+                    .setIntent(intent)
+                    .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_HELP_AND_FEEDBACK)
+                    .build());
+        }
+        intent = mSupportFeatureProvider.getTipsAndTricksIntent(mActivity);
+        if (packageManager.resolveActivity(intent, 0) != null) {
+            mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
+                    .setIcon(R.drawable.ic_lightbulb_outline_24)
+                    .setTileTitle(R.string.support_tips_and_tricks_title)
+                    .setIntent(intent)
+                    .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_TIPS_AND_TRICKS)
+                    .build());
+        }
     }
 
     private void bindEscalationOptions(ViewHolder holder, EscalationData data) {
diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java
index 1d48d5d..758632e 100644
--- a/src/com/android/settings/dashboard/conditional/Condition.java
+++ b/src/com/android/settings/dashboard/conditional/Condition.java
@@ -38,6 +38,12 @@
     // All conditions must live in this package.
     Condition(ConditionManager manager) {
         mManager = manager;
+        Class<?> receiverClass = getReceiverClass();
+        if (receiverClass != null && shouldAlwaysListenToBroadcast()) {
+            PackageManager pm = mManager.getContext().getPackageManager();
+            pm.setComponentEnabledSetting(new ComponentName(mManager.getContext(), receiverClass),
+                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0 /* flag */);
+        }
     }
 
     void restoreState(PersistableBundle bundle) {
@@ -93,6 +99,10 @@
     }
 
     private void onSilenceChanged(boolean silenced) {
+        if (shouldAlwaysListenToBroadcast()) {
+            // Don't try to disable BroadcastReceiver if we want it always on.
+            return;
+        }
         Class<?> clz = getReceiverClass();
         if (clz == null) {
             return;
@@ -109,6 +119,10 @@
         return null;
     }
 
+    protected boolean shouldAlwaysListenToBroadcast() {
+        return false;
+    }
+
     public boolean shouldShow() {
         return isActive() && !isSilenced();
     }
diff --git a/src/com/android/settings/dashboard/conditional/DndCondition.java b/src/com/android/settings/dashboard/conditional/DndCondition.java
index 2a5aa8a..dcab279 100644
--- a/src/com/android/settings/dashboard/conditional/DndCondition.java
+++ b/src/com/android/settings/dashboard/conditional/DndCondition.java
@@ -26,6 +26,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
+
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 
@@ -143,4 +144,9 @@
             }
         }
     }
+
+    @Override
+    protected boolean shouldAlwaysListenToBroadcast() {
+        return true;
+    }
 }
diff --git a/src/com/android/settings/inputmethod/InputMethodPreference.java b/src/com/android/settings/inputmethod/InputMethodPreference.java
index 1d4fa67..2c27700 100755
--- a/src/com/android/settings/inputmethod/InputMethodPreference.java
+++ b/src/com/android/settings/inputmethod/InputMethodPreference.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.inputmethod.InputMethodUtils;
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedSwitchPreference;
 
@@ -142,18 +143,22 @@
         }
         if (isChecked()) {
             // Disable this IME.
-            setChecked(false);
-            mOnSaveListener.onSaveInputMethodPreference(this);
+            setCheckedInternal(false);
             return false;
         }
         if (InputMethodUtils.isSystemIme(mImi)) {
-            // Enable a system IME. No need to show a security warning dialog.
-            setChecked(true);
-            mOnSaveListener.onSaveInputMethodPreference(this);
-            return false;
+            // Enable a system IME. No need to show a security warning dialog,
+            // but we might need to prompt if it's not Direct Boot aware.
+            if (Utils.isPackageDirectBootAware(getContext(), mImi.getPackageName())) {
+                setCheckedInternal(true);
+            } else {
+                showDirectBootWarnDialog();
+            }
+        } else {
+            // Once security is confirmed, we might prompt if the IME isn't
+            // Direct Boot aware.
+            showSecurityWarnDialog();
         }
-        // Enable a 3rd party IME.
-        showSecurityWarnDialog(mImi);
         return false;
     }
 
@@ -218,7 +223,13 @@
                 subtypes, getContext(), mImi);
     }
 
-    private void showSecurityWarnDialog(final InputMethodInfo imi) {
+    private void setCheckedInternal(boolean checked) {
+        super.setChecked(checked);
+        mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
+        notifyChanged();
+    }
+
+    private void showSecurityWarnDialog() {
         if (mDialog != null && mDialog.isShowing()) {
             mDialog.dismiss();
         }
@@ -226,25 +237,50 @@
         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
         builder.setCancelable(true /* cancelable */);
         builder.setTitle(android.R.string.dialog_alert_title);
-        final CharSequence label = imi.getServiceInfo().applicationInfo.loadLabel(
+        final CharSequence label = mImi.getServiceInfo().applicationInfo.loadLabel(
                 context.getPackageManager());
         builder.setMessage(context.getString(R.string.ime_security_warning, label));
         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(final DialogInterface dialog, final int which) {
-                // The user confirmed to enable a 3rd party IME.
-                setChecked(true);
-                mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
-                notifyChanged();
+                // The user confirmed to enable a 3rd party IME, but we might
+                // need to prompt if it's not Direct Boot aware.
+                if (Utils.isPackageDirectBootAware(getContext(), mImi.getPackageName())) {
+                    setCheckedInternal(true);
+                } else {
+                    showDirectBootWarnDialog();
+                }
             }
         });
         builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(final DialogInterface dialog, final int which) {
                 // The user canceled to enable a 3rd party IME.
-                setChecked(false);
-                mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
-                notifyChanged();
+                setCheckedInternal(false);
+            }
+        });
+        mDialog = builder.create();
+        mDialog.show();
+    }
+
+    private void showDirectBootWarnDialog() {
+        if (mDialog != null && mDialog.isShowing()) {
+            mDialog.dismiss();
+        }
+        final Context context = getContext();
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        builder.setCancelable(true /* cancelable */);
+        builder.setMessage(context.getText(R.string.direct_boot_unaware_dialog_message));
+        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(final DialogInterface dialog, final int which) {
+                setCheckedInternal(true);
+            }
+        });
+        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(final DialogInterface dialog, final int which) {
+                setCheckedInternal(false);
             }
         });
         mDialog = builder.create();