Merge "Some clean up of app install and user management." into jb-mr1-dev
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ac3dee4..9051285 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -357,11 +357,6 @@
 
                         // From the Unicode Line Breaking Algorithm (at least approximately)
                         boolean isLineBreak = isSpaceOrTab ||
-                                // .,:; are class IS breakpoints, except when adjacent to digits
-                                ((c == CHAR_DOT || c == CHAR_COMMA ||
-                                c == CHAR_COLON || c == CHAR_SEMICOLON) &&
-                                (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
-                                (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
                                 // / is class SY and - is class HY, except when followed by a digit
                                 ((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
                                 (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
@@ -959,10 +954,6 @@
     private static final char CHAR_NEW_LINE = '\n';
     private static final char CHAR_TAB = '\t';
     private static final char CHAR_SPACE = ' ';
-    private static final char CHAR_DOT = '.';
-    private static final char CHAR_COMMA = ',';
-    private static final char CHAR_COLON = ':';
-    private static final char CHAR_SEMICOLON = ';';
     private static final char CHAR_SLASH = '/';
     private static final char CHAR_HYPHEN = '-';
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 61c942d..423135f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -973,6 +973,12 @@
 
         // Start selection mode if needed. We don't need to if we're unchecking something.
         if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+            if (mMultiChoiceModeCallback == null ||
+                    !mMultiChoiceModeCallback.hasWrappedCallback()) {
+                throw new IllegalStateException("AbsListView: attempted to start selection mode " +
+                        "for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
+                        "supplied. Call setMultiChoiceModeListener to set a callback.");
+            }
             mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
         }
 
@@ -5945,6 +5951,10 @@
             mWrapped = wrapped;
         }
 
+        public boolean hasWrappedCallback() {
+            return mWrapped != null;
+        }
+
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             if (mWrapped.onCreateActionMode(mode, menu)) {
                 // Initialize checked graphic state?
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index f91201a..bc78adc 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -175,11 +175,7 @@
     @Override
     protected void internalSetPadding(int left, int top, int right, int bottom) {
         super.internalSetPadding(left, top, right, bottom);
-        if (isLayoutRtl()) {
-            mBasePadding = mUserPaddingLeft;
-        } else {
-            mBasePadding = mUserPaddingRight;
-        }
+        setBasePadding(isLayoutRtl());
     }
 
     @Override
@@ -201,13 +197,21 @@
     @Override
     public void setPadding(int left, int top, int right, int bottom) {
         super.setPadding(left, top, right, bottom);
-        mBasePadding = getPaddingEnd();
+        setBasePadding(isLayoutRtl());
     }
 
     @Override
     public void setPaddingRelative(int start, int top, int end, int bottom) {
         super.setPaddingRelative(start, top, end, bottom);
-        mBasePadding = getPaddingEnd();
+        setBasePadding(isLayoutRtl());
+    }
+
+    private void setBasePadding(boolean isLayoutRtl) {
+        if (isLayoutRtl) {
+            mBasePadding = mPaddingLeft;
+        } else {
+            mBasePadding = mPaddingRight;
+        }
     }
 
     @Override
@@ -237,11 +241,11 @@
             final int left;
             final int right;
             if (isLayoutRtl) {
-                right = getPaddingEnd();
-                left = right - mCheckMarkWidth;
-            } else {
-                left = width - getPaddingEnd();
+                left = mBasePadding;
                 right = left + mCheckMarkWidth;
+            } else {
+                right = width - mBasePadding;
+                left = right - mCheckMarkWidth;
             }
             checkMarkDrawable.setBounds( left, top, right, bottom);
             checkMarkDrawable.draw(canvas);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 08d9f49..b620568 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -23,7 +23,9 @@
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.view.Gravity;
 import android.view.View;
@@ -38,6 +40,7 @@
 import android.widget.ListView;
 import android.widget.Spinner;
 import android.widget.TextView;
+import android.widget.Toast;
 
 /**
  * This widget implements the dynamic action bar tab behavior that can change
@@ -352,7 +355,7 @@
         tabView.getTab().select();
     }
 
-    private class TabView extends LinearLayout {
+    private class TabView extends LinearLayout implements OnLongClickListener {
         private ActionBar.Tab mTab;
         private TextView mTextView;
         private ImageView mIconView;
@@ -426,7 +429,8 @@
                     mIconView.setImageDrawable(null);
                 }
 
-                if (text != null) {
+                final boolean hasText = !TextUtils.isEmpty(text);
+                if (hasText) {
                     if (mTextView == null) {
                         TextView textView = new TextView(getContext(), null,
                                 com.android.internal.R.attr.actionBarTabTextStyle);
@@ -448,9 +452,35 @@
                 if (mIconView != null) {
                     mIconView.setContentDescription(tab.getContentDescription());
                 }
+
+                if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+                    setOnLongClickListener(this);
+                } else {
+                    setOnLongClickListener(null);
+                    setLongClickable(false);
+                }
             }
         }
 
+        public boolean onLongClick(View v) {
+            final int[] screenPos = new int[2];
+            getLocationOnScreen(screenPos);
+
+            final Context context = getContext();
+            final int width = getWidth();
+            final int height = getHeight();
+            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
+                    Toast.LENGTH_SHORT);
+            // Show under the tab
+            cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
+                    (screenPos[0] + width / 2) - screenWidth / 2, height);
+
+            cheatSheet.show();
+            return true;
+        }
+
         public ActionBar.Tab getTab() {
             return mTab;
         }
diff --git a/docs/downloads/design/Android_Design_Downloads_20120823.zip b/docs/downloads/design/Android_Design_Downloads_20120823.zip
new file mode 100644
index 0000000..6d31283
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Downloads_20120823.zip
Binary files differ
diff --git a/docs/downloads/design/Roboto_Hinted_20120823.zip b/docs/downloads/design/Roboto_Hinted_20120823.zip
new file mode 100644
index 0000000..9ead4af
--- /dev/null
+++ b/docs/downloads/design/Roboto_Hinted_20120823.zip
Binary files differ
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index 4503098..5f78aea 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -12,7 +12,7 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Downloads_20120814.zip">Download All</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Downloads_20120823.zip">Download All</a>
 </p>
 
   </div>
@@ -91,7 +91,7 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="{@docRoot}downloads/design/Roboto_Hinted_20111129.zip">Roboto</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Roboto_Hinted_20120823.zip">Roboto</a>
   <a class="download-button" href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
 </p>
 
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 2d4fa2b..32b3597 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -35,6 +35,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -164,6 +165,8 @@
     private static final int UPDATE_LOCATION = 7;
     private static final int ADD_LISTENER = 8;
     private static final int REMOVE_LISTENER = 9;
+    private static final int INJECT_NTP_TIME_FINISHED = 10;
+    private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
 
     // Request setid
     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
@@ -229,10 +232,15 @@
     // true if we have network connectivity
     private boolean mNetworkAvailable;
 
+    // states for injecting ntp and downloading xtra data
+    private static final int STATE_PENDING_NETWORK = 0;
+    private static final int STATE_DOWNLOADING = 1;
+    private static final int STATE_IDLE = 2;
+
     // flags to trigger NTP or XTRA data download when network becomes available
     // initialized to true so we do NTP and XTRA when the network comes up after booting
-    private boolean mInjectNtpTimePending = true;
-    private boolean mDownloadXtraDataPending = true;
+    private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
+    private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
 
     // set to true if the GPS engine does not do on-demand NTP time requests
     private boolean mPeriodicTimeInjection;
@@ -569,81 +577,105 @@
         }
 
         if (mNetworkAvailable) {
-            if (mInjectNtpTimePending) {
+            if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
                 sendMessage(INJECT_NTP_TIME, 0, null);
             }
-            if (mDownloadXtraDataPending) {
+            if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
                 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
             }
         }
     }
 
     private void handleInjectNtpTime() {
-        if (!mNetworkAvailable) {
-            // try again when network is up
-            mInjectNtpTimePending = true;
+        if (mInjectNtpTimePending == STATE_DOWNLOADING) {
+            // already downloading data
             return;
         }
-        mInjectNtpTimePending = false;
-
-        long delay;
-
-        // force refresh NTP cache when outdated
-        if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
-            mNtpTime.forceRefresh();
+        if (!mNetworkAvailable) {
+            // try again when network is up
+            mInjectNtpTimePending = STATE_PENDING_NETWORK;
+            return;
         }
+        mInjectNtpTimePending = STATE_DOWNLOADING;
 
-        // only update when NTP time is fresh
-        if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
-            long time = mNtpTime.getCachedNtpTime();
-            long timeReference = mNtpTime.getCachedNtpTimeReference();
-            long certainty = mNtpTime.getCacheCertainty();
-            long now = System.currentTimeMillis();
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+            @Override
+            public void run() {
+                long delay;
 
-            Log.d(TAG, "NTP server returned: "
-                    + time + " (" + new Date(time)
-                    + ") reference: " + timeReference
-                    + " certainty: " + certainty
-                    + " system time offset: " + (time - now));
+                // force refresh NTP cache when outdated
+                if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
+                    mNtpTime.forceRefresh();
+                }
 
-            native_inject_time(time, timeReference, (int) certainty);
-            delay = NTP_INTERVAL;
-        } else {
-            if (DEBUG) Log.d(TAG, "requestTime failed");
-            delay = RETRY_INTERVAL;
-        }
+                // only update when NTP time is fresh
+                if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
+                    long time = mNtpTime.getCachedNtpTime();
+                    long timeReference = mNtpTime.getCachedNtpTimeReference();
+                    long certainty = mNtpTime.getCacheCertainty();
+                    long now = System.currentTimeMillis();
 
-        if (mPeriodicTimeInjection) {
-            // send delayed message for next NTP injection
-            // since this is delayed and not urgent we do not hold a wake lock here
-            mHandler.removeMessages(INJECT_NTP_TIME);
-            mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
-        }
+                    Log.d(TAG, "NTP server returned: "
+                            + time + " (" + new Date(time)
+                            + ") reference: " + timeReference
+                            + " certainty: " + certainty
+                            + " system time offset: " + (time - now));
+
+                    native_inject_time(time, timeReference, (int) certainty);
+                    delay = NTP_INTERVAL;
+                } else {
+                    if (DEBUG) Log.d(TAG, "requestTime failed");
+                    delay = RETRY_INTERVAL;
+                }
+
+                mHandler.sendMessage(Message.obtain(mHandler, INJECT_NTP_TIME_FINISHED));
+
+                if (mPeriodicTimeInjection) {
+                    // send delayed message for next NTP injection
+                    // since this is delayed and not urgent we do not hold a wake lock here
+                    mHandler.removeMessages(INJECT_NTP_TIME);
+                    mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+                }
+            }
+        });
     }
 
     private void handleDownloadXtraData() {
-        if (!mNetworkAvailable) {
-            // try again when network is up
-            mDownloadXtraDataPending = true;
+        if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
+            // already downloading data
             return;
         }
-        mDownloadXtraDataPending = false;
-
-
-        GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
-        byte[] data = xtraDownloader.downloadXtraData();
-        if (data != null) {
-            if (DEBUG) {
-                Log.d(TAG, "calling native_inject_xtra_data");
-            }
-            native_inject_xtra_data(data, data.length);
-        } else {
-            // try again later
-            // since this is delayed and not urgent we do not hold a wake lock here
-            mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
-            mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA),
-                    RETRY_INTERVAL);
+        if (!mNetworkAvailable) {
+            // try again when network is up
+            mDownloadXtraDataPending = STATE_PENDING_NETWORK;
+            return;
         }
+        mDownloadXtraDataPending = STATE_DOWNLOADING;
+
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+            @Override
+            public void run() {
+                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
+                byte[] data = xtraDownloader.downloadXtraData();
+                if (data != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "calling native_inject_xtra_data");
+                    }
+                    native_inject_xtra_data(data, data.length);
+                }
+
+                mHandler.sendMessage(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA_FINISHED));
+
+                if (data == null) {
+                    // try again later
+                    // since this is delayed and not urgent we do not hold a wake lock here
+                    mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+                    mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA),
+                            RETRY_INTERVAL);
+                }
+            }
+
+        });
     }
 
     private void handleUpdateLocation(Location location) {
@@ -1474,6 +1506,12 @@
                         handleDownloadXtraData();
                     }
                     break;
+                case INJECT_NTP_TIME_FINISHED:
+                    mInjectNtpTimePending = STATE_IDLE;
+                    break;
+                case DOWNLOAD_XTRA_DATA_FINISHED:
+                    mDownloadXtraDataPending = STATE_IDLE;
+                    break;
                 case UPDATE_LOCATION:
                     handleUpdateLocation((Location)msg.obj);
                     break;