Merge "Fix issue #10948509: Crash in procstats when there is no data" into klp-dev
diff --git a/res/layout/nfc_payment.xml b/res/layout/nfc_payment.xml
index 54ac403..d6f9fa4 100644
--- a/res/layout/nfc_payment.xml
+++ b/res/layout/nfc_payment.xml
@@ -23,6 +23,18 @@
             android:visibility="gone"
             android:paddingTop="16dp"
             android:text="@string/nfc_payment_no_apps"/>
+        <TextView
+            android:id="@+id/nfc_payment_learn_more"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:clickable="true"
+            android:textSize="20sp"
+            android:textStyle="italic"
+            android:visibility="gone"
+            android:textColor="@android:color/holo_blue_light"
+            android:paddingTop="16dp"
+            android:text="@string/nfc_payment_learn_more"/>
     </LinearLayout>
     <ListView
         android:id="@android:id/list"
diff --git a/res/layout/printer_dropdown_item.xml b/res/layout/printer_dropdown_item.xml
new file mode 100644
index 0000000..ad393b8
--- /dev/null
+++ b/res/layout/printer_dropdown_item.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="48dip"
+    android:gravity="center_vertical"
+    android:paddingStart="@*android:dimen/preference_item_padding_side"
+    android:paddingEnd="?android:attr/scrollbarSize"
+    android:background="?android:attr/selectableItemBackground">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="32dip"
+        android:layout_height="32dip"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="8dip"
+        android:duplicateParentState="true"
+        android:contentDescription="@null"
+        android:visibility="gone">
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:textIsSelectable="false">
+        </TextView>
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:textIsSelectable="false"
+            android:visibility="gone"
+            android:textColor="?android:attr/textColorSecondary">
+        </TextView>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index bd385f6..40098f5 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -35,7 +35,8 @@
 
     <color name="divider_color">#20ffffff</color>
     <color name="title_color">@android:color/holo_blue_light</color>
-    <color name="setup_divider_color">#333333</color>
+    <color name="setup_divider_color_dark">#33ffffff</color>
+    <color name="setup_divider_color_light">#33000000</color>
 
     <color name="circle_avatar_frame_color">#ffffffff</color>
     <color name="circle_avatar_frame_shadow_color">#80000000</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79a4c92..3c45bbc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4778,7 +4778,10 @@
     <!-- NFC payment settings --><skip/>
     <string name="nfc_payment_settings_title">Tap &amp; pay</string>
     <!-- String shown when there are no NFC payment applications installed -->
-    <string name="nfc_payment_no_apps">You have no apps configured for tap &amp; pay with NFC.</string>
+    <string name="nfc_payment_no_apps">Pay with just a tap</string>
+    <!-- String shown when there are no NFC payment applications installed, clickable, pointing to
+         a website to learn more-->
+    <string name="nfc_payment_learn_more">Learn more</string>
     <string name="nfc_payment_menu_item_add_service">Find apps</string>
     <!-- Label for the dialog that is shown when the user is asked to set a
          preferred payment application -->
@@ -4830,6 +4833,8 @@
     <string name="help_url_location_access" translatable="false"></string>
     <!-- Help URL, Security settings [DO NOT TRANSLATE] -->
     <string name="help_url_security" translatable="false"></string>
+    <!-- Help URL, Tap & pay [DO NOT TRANSLATE] -->
+    <string name="help_url_nfc_payment" translatable="false"></string>
 
     <!-- User account title [CHAR LIMIT=30] -->
     <string name="user_account_title">Account for content</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4805cb6..eee2cd9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -130,7 +130,7 @@
     <style name="TopDivider">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">@dimen/divider_height</item>
-        <item name="android:background">@color/setup_divider_color</item>
+        <item name="android:background">?attr/setup_divider_color</item>
         <item name="android:focusable">false</item>
         <item name="android:clickable">false</item>
         <item name="android:layout_marginTop">@dimen/divider_margin_top</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 19d1e91..a87ad33 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -18,6 +18,7 @@
     <attr name="ic_menu_add" format="reference" />
     <attr name="ic_menu_moreoverflow" format="reference" />
     <attr name="ic_wps" format="reference" />
+    <attr name="setup_divider_color" format="reference" />
     <attr name="wifi_signal" format="reference" />
 
     <style name="SetupWizardWifiTheme" parent="android:Theme.Holo.NoActionBar">
@@ -27,6 +28,7 @@
         <item name="ic_menu_add">@drawable/ic_menu_add_dark</item>
         <item name="ic_menu_moreoverflow">@*android:drawable/ic_menu_moreoverflow_holo_dark</item>
         <item name="ic_wps">@drawable/ic_wps_dark</item>
+        <item name="setup_divider_color">@color/setup_divider_color_dark</item>
         <item name="wifi_signal">@drawable/wifi_signal_dark</item>
     </style>
 
@@ -37,6 +39,7 @@
         <item name="ic_menu_add">@drawable/ic_menu_add_light</item>
         <item name="ic_menu_moreoverflow">@*android:drawable/ic_menu_moreoverflow_holo_light</item>
         <item name="ic_wps">@drawable/ic_wps_light</item>
+        <item name="setup_divider_color">@color/setup_divider_color_light</item>
         <item name="wifi_signal">@drawable/wifi_signal_light</item>
     </style>
 
diff --git a/src/com/android/settings/HelpUtils.java b/src/com/android/settings/HelpUtils.java
index 6cd5eb6..22e2f76 100644
--- a/src/com/android/settings/HelpUtils.java
+++ b/src/com/android/settings/HelpUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.settings;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -95,9 +96,15 @@
 
             // Set the intent to the help menu item, show the help menu item in the overflow
             // menu, and make it visible.
-            helpMenuItem.setIntent(intent);
-            helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-            helpMenuItem.setVisible(true);
+            ComponentName component = intent.resolveActivity(context.getPackageManager());
+            if (component != null) {
+                helpMenuItem.setIntent(intent);
+                helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+                helpMenuItem.setVisible(true);
+            } else {
+                helpMenuItem.setVisible(false);
+                return false;
+            }
 
             // return that the help menu item is visible (i.e., true)
             return true;
@@ -109,7 +116,7 @@
      * of the app's package as gotten via the context.
      * @return the uri with added query parameters
      */
-    private static Uri uriWithAddedParameters(Context context, Uri baseUri) {
+    public static Uri uriWithAddedParameters(Context context, Uri baseUri) {
         Uri.Builder builder = baseUri.buildUpon();
 
         // Add in the preferred language
diff --git a/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java
index 3934646..f3c8b1c 100644
--- a/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java
@@ -92,6 +92,8 @@
                 final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
                         activity, locale, R.string.captioning_preview_text);
                 preview.setText(localizedText);
+            } else {
+                preview.setText(R.string.captioning_preview_text);
             }
         }
     }
@@ -110,6 +112,8 @@
             final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
                     context, locale, R.string.captioning_preview_characters);
             previewText.setText(localizedText);
+        } else {
+            previewText.setText(R.string.captioning_preview_characters);
         }
     }
 
diff --git a/src/com/android/settings/location/RecentLocationApps.java b/src/com/android/settings/location/RecentLocationApps.java
index 3cd5406..9488db7 100644
--- a/src/com/android/settings/location/RecentLocationApps.java
+++ b/src/com/android/settings/location/RecentLocationApps.java
@@ -20,6 +20,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -44,12 +45,15 @@
 public class RecentLocationApps {
     private static final String TAG = RecentLocationApps.class.getSimpleName();
     private static final String ANDROID_SYSTEM_PACKAGE_NAME = "android";
+    private static final String GOOGLE_SERVICES_SHARED_UID = "com.google.uid.shared";
+    private static final String GCORE_PACKAGE_NAME = "com.google.android.gms";
 
     private static final int RECENT_TIME_INTERVAL_MILLIS = 15 * 60 * 1000;
 
     private final PreferenceActivity mActivity;
     private final BatteryStatsHelper mStatsHelper;
     private final PackageManager mPackageManager;
+    private final Drawable mGCoreIcon;
 
     // Stores all the packages that requested location within the designated interval
     // key - package name of the app
@@ -59,6 +63,18 @@
         mActivity = activity;
         mPackageManager = activity.getPackageManager();
         mStatsHelper = sipperUtil;
+        Drawable icon = null;
+        try {
+            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+                    GCORE_PACKAGE_NAME, PackageManager.GET_META_DATA);
+            icon = mPackageManager.getApplicationIcon(appInfo);
+        } catch (PackageManager.NameNotFoundException e) {
+            if (Log.isLoggable(TAG, Log.INFO)) {
+                Log.i(TAG, "GCore not installed");
+            }
+            icon = null;
+        }
+        mGCoreIcon = icon;
     }
 
     private class UidEntryClickedListener
@@ -187,6 +203,42 @@
     }
 
     /**
+     * Retrieves the icon for given BatterySipper object.
+     *
+     * The icons on location blaming page are actually Uid-based rather than package based. For
+     * those packages that share the same Uid, BatteryStatsHelper picks the one with the most CPU
+     * usage. Both "Contact Sync" and GCore belong to "Google Services" and they share the same Uid.
+     * As a result, sometimes Contact icon may be chosen to represent "Google Services" by
+     * BatteryStatsHelper.
+     *
+     * In order to avoid displaying Contact icon for "Google Services", we hack this method to
+     * always return Puzzle icon for all packages that share the Uid of "Google Services".
+     */
+    private Drawable getIcon(BatterySipper sipper, AppOpsManager.PackageOps ops) {
+        Drawable icon = null;
+        if (mGCoreIcon != null) {
+            try {
+                PackageInfo info = mPackageManager.getPackageInfo(
+                        ops.getPackageName(), PackageManager.GET_META_DATA);
+                if (info != null && GOOGLE_SERVICES_SHARED_UID.equals(info.sharedUserId)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "shareUserId matches GCore, force using puzzle icon");
+                    }
+                    icon = mGCoreIcon;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, e.toString());
+                }
+            }
+        }
+        if (icon == null) {
+            icon = sipper.getIcon();
+        }
+        return icon;
+    }
+
+    /**
      * Creates a Preference entry for the given PackageOps.
      *
      * This method examines the time interval of the PackageOps first. If the PackageOps is older
@@ -241,7 +293,7 @@
                 BatterySipper sipper = wrapper.batterySipper();
                 sipper.loadNameAndIcon();
                 pref = createRecentLocationEntry(
-                        sipper.getIcon(),
+                        getIcon(sipper, ops),
                         sipper.getLabel(),
                         highBattery,
                         new UidEntryClickedListener(sipper));
diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java
index f839b24..06697a4 100644
--- a/src/com/android/settings/nfc/PaymentSettings.java
+++ b/src/com/android/settings/nfc/PaymentSettings.java
@@ -25,6 +25,7 @@
 import android.preference.Preference;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -38,6 +39,7 @@
 import android.widget.TextView;
 
 import com.android.internal.content.PackageMonitor;
+import com.android.settings.HelpUtils;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.nfc.PaymentBackend.PaymentAppInfo;
@@ -49,7 +51,6 @@
     public static final String TAG = "PaymentSettings";
     private LayoutInflater mInflater;
     private PaymentBackend mPaymentBackend;
-
     private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
 
 
@@ -57,7 +58,6 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        setHasOptionsMenu(false);
         mPaymentBackend = new PaymentBackend(getActivity());
         mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         setHasOptionsMenu(true);
@@ -83,13 +83,18 @@
             }
         }
         TextView emptyText = (TextView) getView().findViewById(R.id.nfc_payment_empty_text);
+        TextView learnMore = (TextView) getView().findViewById(R.id.nfc_payment_learn_more);
         ImageView emptyImage = (ImageView) getView().findViewById(R.id.nfc_payment_tap_image);
         if (screen.getPreferenceCount() == 0) {
             emptyText.setVisibility(View.VISIBLE);
+            learnMore.setVisibility(View.VISIBLE);
             emptyImage.setVisibility(View.VISIBLE);
+            getListView().setVisibility(View.GONE);
         } else {
             emptyText.setVisibility(View.GONE);
+            learnMore.setVisibility(View.GONE);
             emptyImage.setVisibility(View.GONE);
+            getListView().setVisibility(View.VISIBLE);
         }
         setPreferenceScreen(screen);
     }
@@ -99,6 +104,24 @@
             Bundle savedInstanceState) {
         super.onCreateView(inflater, container, savedInstanceState);
         View v = mInflater.inflate(R.layout.nfc_payment, container, false);
+        TextView learnMore = (TextView) v.findViewById(R.id.nfc_payment_learn_more);
+        learnMore.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                String helpUrl;
+                if (!TextUtils.isEmpty(helpUrl = getResources().getString(
+                        R.string.help_url_nfc_payment))) {
+                    final Uri fullUri = HelpUtils.uriWithAddedParameters(
+                            PaymentSettings.this.getActivity(), Uri.parse(helpUrl));
+                    Intent intent = new Intent(Intent.ACTION_VIEW, fullUri);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                    startActivity(intent);
+                } else {
+                    Log.e(TAG, "Help url not set.");
+                }
+            }
+        });
         return v;
     }
 
@@ -190,4 +213,4 @@
             banner.setImageDrawable(appInfo.banner);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
index d2d8525..9db2dec 100644
--- a/src/com/android/settings/print/PrintServiceSettingsFragment.java
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -32,6 +32,9 @@
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -54,6 +57,7 @@
 import android.widget.CompoundButton;
 import android.widget.Filter;
 import android.widget.Filterable;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.SearchView;
 import android.widget.TextView;
@@ -293,7 +297,7 @@
             }
         });
 
-        getListView().setEnabled(false);
+        getListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
         getListView().setAdapter(mPrintersAdapter);
     }
 
@@ -531,24 +535,26 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = getActivity().getLayoutInflater().inflate(
-                        R.layout.preference, parent, false);
+                        R.layout.printer_dropdown_item, parent, false);
             }
 
             PrinterInfo printer = (PrinterInfo) getItem(position);
             CharSequence title = printer.getName();
             CharSequence subtitle = null;
+            Drawable icon = null;
             try {
                 PackageInfo packageInfo = getPackageManager().getPackageInfo(
                         printer.getId().getServiceName().getPackageName(), 0);
                         subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
+                        icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
             } catch (NameNotFoundException nnfe) {
                 /* ignore */
             }
 
-            TextView titleView = (TextView) convertView.findViewById(android.R.id.title);
+            TextView titleView = (TextView) convertView.findViewById(R.id.title);
             titleView.setText(title);
 
-            TextView subtitleView = (TextView) convertView.findViewById(android.R.id.summary);
+            TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
             if (!TextUtils.isEmpty(subtitle)) {
                 subtitleView.setText(subtitle);
                 subtitleView.setVisibility(View.VISIBLE);
@@ -557,6 +563,14 @@
                 subtitleView.setVisibility(View.GONE);
             }
 
+            ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+            if (icon != null) {
+                iconView.setImageDrawable(icon);
+                iconView.setVisibility(View.VISIBLE);
+            } else {
+                iconView.setVisibility(View.GONE);
+            }
+
             return convertView;
         }