OSDN Git Service

Merge "Make NetworkMonitor less aggressive on broken networks." into lmp-mr1-dev
authorLorenzo Colitti <lorenzo@google.com>
Tue, 27 Jan 2015 11:41:08 +0000 (11:41 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 27 Jan 2015 11:41:10 +0000 (11:41 +0000)
32 files changed:
api/system-current.txt
core/java/android/app/Activity.java
core/java/android/app/Dialog.java
core/java/android/view/View.java
core/java/android/view/ViewGroup.java
core/java/android/widget/HorizontalScrollView.java
core/java/android/widget/ListPopupWindow.java
core/java/android/widget/RadialTimePickerView.java
core/java/android/widget/Toolbar.java
core/java/com/android/internal/widget/ActionBarContainer.java
core/res/res/drawable/ic_corp_badge.xml
core/res/res/drawable/ic_corp_icon_badge.xml
core/res/res/values-television/config.xml [new file with mode: 0644]
core/res/res/values-zh-rCN/strings.xml
docs/html/training/location/display-address.jd
docs/html/training/wearables/data-layer/data-items.jd
docs/html/training/wearables/data-layer/events.jd
media/java/android/mtp/MtpDatabase.java
media/java/android/mtp/MtpPropertyGroup.java
media/jni/android_mtp_MtpDatabase.cpp
packages/PrintSpooler/res/values-ca/arrays.xml [new file with mode: 0644]
policy/src/com/android/internal/policy/impl/PhoneWindow.java
services/core/java/com/android/server/am/ActiveServices.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityRecord.java
services/core/java/com/android/server/am/ActivityStack.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/am/EventLogTags.logtags
services/core/java/com/android/server/tv/TvInputHardwareManager.java
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
telecomm/java/android/telecom/TelecomManager.java
telecomm/java/com/android/internal/telecom/ITelecomService.aidl

index 39685ae..56edc72 100644 (file)
@@ -30341,6 +30341,7 @@ package android.telecom {
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String);
     method public android.content.ComponentName getDefaultPhoneApp();
+    method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
index 38cd126..d33c82b 100644 (file)
@@ -2377,8 +2377,10 @@ public class Activity extends ContextThemeWrapper
         if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
             return false;
         } else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
-            if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
-                    keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
+            Window w = getWindow();
+            if (w.hasFeature(Window.FEATURE_OPTIONS_PANEL) &&
+                    w.performPanelShortcut(Window.FEATURE_OPTIONS_PANEL, keyCode, event,
+                            Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
                 return true;
             }
             return false;
@@ -2943,7 +2945,8 @@ public class Activity extends ContextThemeWrapper
      * time it needs to be displayed.
      */
     public void invalidateOptionsMenu() {
-        if (mActionBar == null || !mActionBar.invalidateOptionsMenu()) {
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) &&
+                (mActionBar == null || !mActionBar.invalidateOptionsMenu())) {
             mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
         }
     }
@@ -3155,7 +3158,8 @@ public class Activity extends ContextThemeWrapper
      * open, this method does nothing.
      */
     public void openOptionsMenu() {
-        if (mActionBar == null || !mActionBar.openOptionsMenu()) {
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) &&
+                (mActionBar == null || !mActionBar.openOptionsMenu())) {
             mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);
         }
     }
@@ -3165,7 +3169,9 @@ public class Activity extends ContextThemeWrapper
      * closed, this method does nothing.
      */
     public void closeOptionsMenu() {
-        mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
+        }
     }
 
     /**
index 12d4513..067073a 100644 (file)
@@ -910,21 +910,27 @@ public class Dialog implements DialogInterface, Window.Callback,
      * @see Activity#openOptionsMenu()
      */
     public void openOptionsMenu() {
-        mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);
+        }
     }
-    
+
     /**
      * @see Activity#closeOptionsMenu()
      */
     public void closeOptionsMenu() {
-        mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
+        }
     }
 
     /**
      * @see Activity#invalidateOptionsMenu()
      */
     public void invalidateOptionsMenu() {
-        mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
+        }
     }
 
     /**
index 6a36c26..ed75de3 100644 (file)
@@ -5932,23 +5932,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         return true;
     }
 
-    /**
-     * Adds the clickable rectangles withing the bounds of this view. They
-     * may overlap. This method is intended for use only by the accessibility
-     * layer.
-     *
-     * @param outRects List to which to add clickable areas.
-     *
-     * @hide
-     */
-    public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        if (isClickable() || isLongClickable()) {
-            RectF bounds = new RectF();
-            bounds.set(0, 0, getWidth(), getHeight());
-            outRects.add(bounds);
-        }
-    }
-
     static void offsetRects(List<RectF> rects, float offsetX, float offsetY) {
         final int rectCount = rects.size();
         for (int i = 0; i < rectCount; i++) {
@@ -16650,6 +16633,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
 
         if (changed) {
             requestLayout();
+            invalidateOutline();
         }
     }
 
index a09837d..0b1a2d4 100644 (file)
@@ -855,27 +855,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
 
             // Compute the intersection between the child and the sibling.
             if (siblingBounds.intersect(bounds)) {
-                List<RectF> clickableRects = new ArrayList<>();
-                sibling.addClickableRectsForAccessibility(clickableRects);
-
-                final int clickableRectCount = clickableRects.size();
-                for (int j = 0; j < clickableRectCount; j++) {
-                    RectF clickableRect = clickableRects.get(j);
-
-                    // Translate the clickable rect to our coordinates.
-                    offsetChildRectToMyCoords(clickableRect, sibling);
-
-                    // Compute the intersection between the child and the clickable rects.
-                    if (clickableRect.intersect(bounds)) {
-                        // If a clickable rect completely covers the child, done.
-                        if (clickableRect.equals(bounds)) {
-                            releaseOrderedChildIterator();
-                            return false;
-                        }
-                        // Keep track of the intersection rectangle.
-                        intersections.add(clickableRect);
-                    }
-                }
+                // Conservatively we consider an overlapping sibling to be
+                // interactive and ignore it. This is not ideal as if the
+                // sibling completely covers the view despite handling no
+                // touch events we will not be able to click on the view.
+                intersections.add(siblingBounds);
             }
         }
 
@@ -890,54 +874,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         return true;
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        int sizeBefore = outRects.size();
-
-        super.addClickableRectsForAccessibility(outRects);
-
-        // If we added ourselves, then no need to visit children.
-        if (outRects.size() > sizeBefore) {
-            return;
-        }
-
-        Iterator<View> iterator = obtainOrderedChildIterator();
-        while (iterator.hasNext()) {
-            View child = iterator.next();
-
-            // Cannot click on an invisible view.
-            if (!isVisible(child)) {
-                continue;
-            }
-
-            sizeBefore = outRects.size();
-
-            // Add clickable rects in the child bounds.
-            child.addClickableRectsForAccessibility(outRects);
-
-            // Offset the clickable rects for out children to our coordinates.
-            final int sizeAfter = outRects.size();
-            for (int j = sizeBefore; j < sizeAfter; j++) {
-                RectF rect = outRects.get(j);
-
-                // Translate the clickable rect to our coordinates.
-                offsetChildRectToMyCoords(rect, child);
-
-                // If a clickable rect fills the parent, done.
-                if ((int) rect.left == 0 && (int) rect.top == 0
-                        && (int) rect.right == mRight && (int) rect.bottom == mBottom) {
-                    releaseOrderedChildIterator();
-                    return;
-                }
-            }
-        }
-
-        releaseOrderedChildIterator();
-    }
-
     private void offsetChildRectToMyCoords(RectF rect, View child) {
         if (!child.hasIdentityMatrix()) {
             child.getMatrix().mapRect(rect);
index 371b480..1b93b97 100644 (file)
@@ -762,18 +762,6 @@ public class HorizontalScrollView extends FrameLayout {
         awakenScrollBars();
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        // This class always consumes touch events, therefore if it
-        // covers a view we do not want to send a click over it.
-        RectF bounds = new RectF();
-        bounds.set(0, 0, getWidth(), getHeight());
-        outRects.add(bounds);
-    }
-
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         if (super.performAccessibilityAction(action, arguments)) {
index fe8b08b..d85bbb9 100644 (file)
@@ -1648,19 +1648,32 @@ public class ListPopupWindow {
         private void setPressedItem(View child, int position, float x, float y) {
             mDrawsInPressedState = true;
 
-            // Ordering is essential. First update the pressed state and layout
-            // the children. This will ensure the selector actually gets drawn.
-            setPressed(true);
-            layoutChildren();
+            // Ordering is essential. First, update the container's pressed state.
+            drawableHotspotChanged(x, y);
+            if (!isPressed()) {
+                setPressed(true);
+            }
+
+            // Next, run layout if we need to stabilize child positions.
+            if (mDataChanged) {
+                layoutChildren();
+            }
 
             // Manage the pressed view based on motion position. This allows us to
             // play nicely with actual touch and scroll events.
             final View motionView = getChildAt(mMotionPosition - mFirstPosition);
-            if (motionView != null) {
+            if (motionView != null && motionView != child && motionView.isPressed()) {
                 motionView.setPressed(false);
             }
             mMotionPosition = position;
-            child.setPressed(true);
+
+            // Offset for child coordinates.
+            final float childX = x - child.getLeft();
+            final float childY = y - child.getTop();
+            child.drawableHotspotChanged(childX, childY);
+            if (!child.isPressed()) {
+                child.setPressed(true);
+            }
 
             // Ensure that keyboard focus starts from the last touched position.
             setSelectedPositionInt(position);
index 7b64cf5..11fda2c 100644 (file)
@@ -1381,11 +1381,19 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
         @Override
         protected int getVirtualViewAt(float x, float y) {
             final int id;
+
+            // Calling getDegreesXY() has side-effects, so we need to cache the
+            // current inner circle value and restore after the call.
+            final boolean wasOnInnerCircle = mIsOnInnerCircle;
             final int degrees = getDegreesFromXY(x, y);
+            final boolean isOnInnerCircle = mIsOnInnerCircle;
+            mIsOnInnerCircle = wasOnInnerCircle;
+
             if (degrees != -1) {
                 final int snapDegrees = snapOnly30s(degrees, 0) % 360;
                 if (mShowHours) {
-                    final int hour = getHourForDegrees(snapDegrees, mIsOnInnerCircle);
+                    final int hour24 = getHourForDegrees(snapDegrees, isOnInnerCircle);
+                    final int hour = mIs24HourMode ? hour24 : hour24To12(hour24);
                     id = makeId(TYPE_HOUR, hour);
                 } else {
                     final int current = getCurrentMinute();
@@ -1514,6 +1522,16 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
             return hour24;
         }
 
+        private int hour24To12(int hour24) {
+            if (hour24 == 0) {
+                return 12;
+            } else if (hour24 > 12) {
+                return hour24 - 12;
+            } else {
+                return hour24;
+            }
+        }
+
         private void getBoundsForVirtualView(int virtualViewId, Rect bounds) {
             final float radius;
             final int type = getTypeFromId(virtualViewId);
index 0f35e0d..c5325c4 100644 (file)
@@ -1101,18 +1101,6 @@ public class Toolbar extends ViewGroup {
      * @hide
      */
     @Override
-    public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        // This class always consumes touch events, therefore if it
-        // covers a view we do not want to send a click over it.
-        RectF bounds = new RectF();
-        bounds.set(0, 0, getWidth(), getHeight());
-        outRects.add(bounds);
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     protected void onSetLayoutParams(View child, ViewGroup.LayoutParams lp) {
         /*
          * Apps may set ActionBar.LayoutParams on their action bar custom views when
index e8e2c8d..7937a95 100644 (file)
@@ -227,18 +227,6 @@ public class ActionBarContainer extends FrameLayout {
         return true;
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void addClickableRectsForAccessibility(List<RectF> outRects) {
-        // This class always consumes touch events, therefore if it
-        // covers a view we do not want to send a click over it.
-        RectF bounds = new RectF();
-        bounds.set(0, 0, getWidth(), getHeight());
-        outRects.add(bounds);
-    }
-
     @Override
     public boolean onHoverEvent(MotionEvent ev) {
         super.onHoverEvent(ev);
index 3a66507..8917431 100644 (file)
@@ -14,23 +14,20 @@ Copyright (C) 2014 The Android Open Source Project
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="19.0dp"
-        android:height="19.0dp"
-        android:viewportWidth="19.0"
-        android:viewportHeight="19.0">
+        android:width="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="20.0"
+        android:viewportHeight="20.0">
     <path
-        android:pathData="M9.5,9.5m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0"
+        android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0"
         android:fillColor="#FF5722"/>
     <path
-        android:pathData="M13.741,6.286l-1.53,0L12.211,5.247l-1.039,-1.039L8.025,4.208L6.986,5.247l0,1.039L5.429,6.286c-0.574,0 -1.034,0.465 -1.034,1.039L4.39,13.039c0.0,0.574 0.465,1.039 1.039,1.039l8.312,0c0.574,0 1.039,-0.465 1.039,-1.039L14.780001,7.325C14.78,6.751 14.316,6.286 13.741,6.286zM11.173,6.286L8.025,6.286L8.025,5.247l3.147,0L11.172,6.286z"
+        android:pathData="M15.2,6.2L4.8,6.2c-0.5,0.0 -0.9,0.4 -0.9,1.0L3.9,10.0c0.0,0.5 0.4,1.0 0.9,1.0l3.8,0.0l0.0,-1.0l2.9,0.0l0.0,1.0l3.8,0.0c0.5,0.0 1.0,-0.4 1.0,-1.0L16.3,7.1C16.2,6.6 15.8,6.2 15.2,6.2z"
         android:fillColor="#FFFFFF"/>
     <path
-        android:pathData="M15.172,7.039c0.0,-0.58 -0.501,-1.05 -1.12,-1.05L5.113,5.989c-0.619,0 -1.115,0.47 -1.115,1.05l0.002,2.193c0,0.618 0.5,1.118 1.118,1.118l8.931,0c0.618,0 1.118,-0.5 1.118,-1.118L15.172,7.039z"
+        android:pathData="M8.6,12.9l0.0,-1.0L4.3,11.9l0.0,2.4c0.0,0.5 0.4,0.9 0.9,0.9l9.5,0.0c0.5,0.0 0.9,-0.4 0.9,-0.9l0.0,-2.4l-4.3,0.0l0.0,1.0L8.6,12.9z"
         android:fillColor="#FFFFFF"/>
     <path
-        android:pathData="M3.5,9.812l12,0l0,1l-12,0z"
-        android:fillColor="#FF5722"/>
-    <path
-        android:pathData="M8.567,9.467l2.037,0l0,2.037l-2.037,0z"
-        android:fillColor="#FF5722"/>
+        android:pathData="M7.1,5.2l0.0,1.0 1.0,0.0 0.0,-1.0 3.799999,0.0 0.0,1.0 1.0,0.0 0.0,-1.0 -1.0,-0.9 -3.799999,0.0z"
+        android:fillColor="#FFFFFF"/>
 </vector>
index 538dade..0273545 100644 (file)
@@ -20,25 +20,22 @@ Copyright (C) 2014 The Android Open Source Project
         android:viewportHeight="64.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M49.062,50.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
+        android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
         android:fillAlpha="0.2"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M49.0,49.5m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
+        android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
         android:fillAlpha="0.2"/>
     <path
-        android:pathData="M49.0,49.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
+        android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
         android:fillColor="#FF5722"/>
     <path
-        android:pathData="M55.801,43.688l-2.837,-0.001l0.0,-1.137l-1.587,-1.588l-4.72,-0.001l-1.588,1.587l0.0,1.137l-2.867,-0.001c-0.94,0.0 -1.691,0.76 -1.691,1.699L40.5,48.654c0.0,0.94 0.76,1.7 1.699,1.7l5.255,0.001l0.0,-1.271l0.225,0.0l2.589,0.0l0.225,0.0l0.0,1.271l5.303,0.001c0.939,0.0 1.7,-0.76 1.7,-1.699l0.002,-3.269C57.5,44.449 56.74,43.689 55.801,43.688zM51.377,43.687l-4.72,-0.001l0.0,-1.137l4.72,0.001L51.377,43.687z"
+        android:pathData="M56.4,43.5L41.8,43.5c-0.7,0.0 -1.3,0.6 -1.3,1.3l0.0,4.0c0.0,0.7 0.6,1.3 1.3,1.3L47.0,50.1l0.0,-1.3l4.0,0.0l0.0,1.4l5.4,0.0c0.7,0.0 1.3,-0.6 1.3,-1.3l0.0,-4.0C57.6,44.1 57.0,43.5 56.4,43.5z"
         android:fillColor="#FFFFFF"/>
     <path
-        android:pathData="M50.494,52.012l-3.04,0.0l0.0,-0.901l-6.417,0.0l0.0,3.172c0.0,0.94 0.741,1.7 1.68,1.7l12.464,0.003c0.939,0.0 1.702,-0.76 1.703,-1.699l0.0,-3.176l-6.39,0.0L50.494,52.012z"
+        android:pathData="M47.1,52.8l0.0,-1.3l-6.0,0.0l0.0,3.3c0.0,0.7 0.6,1.3 1.3,1.3l13.2,0.0c0.7,0.0 1.3,-0.6 1.3,-1.3l0.0,-3.3l-6.0,0.0l0.0,1.3L47.1,52.8z"
         android:fillColor="#FFFFFF"/>
     <path
-        android:pathData="M40.726,40.726 h16.13 v16.13 h-16.13z"
-        android:fillColor="#00000000"/>
-    <path
-        android:pathData="M46.657,42.55 h4.72 v1.137 h-4.72z"
-        android:fillColor="#00000000"/>
+        android:pathData="M45.1,42.2l0.0,1.299999 1.300003,0.0 0.0,-1.299999 5.299999,0.0 0.0,1.299999 1.399998,0.0 0.0,-1.299999 -1.399998,-1.299999 -5.299999,0.0z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
new file mode 100644 (file)
index 0000000..3435474
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for TV products.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Flags enabling default window features. See Window.java -->
+    <bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
+</resources>
index 24ec7ce..0c28c86 100644 (file)
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"允许应用调用默认的容器服务,以便复制内容。普通应用不应使用此权限。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"更改媒体输出线路"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允许该应用将媒体输出线路更改到其他外部设备。"</string>
-    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"访问密钥保护安全存储空间"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"访问锁屏安全存储空间"</string>
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允许应用访问密钥保护安全存储空间。"</string>
-    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制是显示还是隐藏锁屏"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制锁屏界面的显示和隐藏状态"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"允许应用控制锁屏。"</string>
     <string name="permlab_trust_listener" msgid="1765718054003704476">"检测信任状态的变化。"</string>
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
index 621b082..516f14f 100644 (file)
 page.title=Displaying a Location Address
-
 trainingnavtop=true
-
 @jd:body
 
-
-
 <div id="tb-wrapper">
-<div id="tb">
+  <div id="tb">
 
-<h2>This lesson teaches you to</h2>
-<ol>
-  <li><a href="#DefineTask">Define the Address Lookup Task</a></li>
-  <li><a href="#DisplayResults">Define a Method to Display the Results</a></li>
-  <li><a href="#RunTask">Run the Lookup Task</a></li>
-</ol>
+    <h2>This lesson teaches you how to</h2>
+    <ol>
+      <li><a href="#connect">Get a Geographic Location</a></li>
+      <li><a href="#fetch-address">Define an Intent Service to Fetch the
+        Address</a></li>
+      <li><a href="#start-intent">Start the Intent Service</a></li>
+      <li><a href="#result-receiver">Receive the Geocoding Results</a></li>
+    </ol>
 
-<h2>You should also read</h2>
-<ul>
-    <li>
-        <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
-    </li>
-    <li>
-        <a href="retrieve-current.html">Retrieving the Current Location</a>
-    </li>
-    <li>
-        <a href="receive-location-updates.html">Receiving Location Updates</a>
-    </li>
-</ul>
-<h2>Try it out</h2>
+    <h2>You should also read</h2>
+      <ul>
+        <li>
+          <a href="{@docRoot}google/play-services/setup.html">Setting up Google
+          Play Services</a>
+        </li>
+        <li>
+          <a href="retrieve-current.html">Getting the Last Known Location</a>
+        </li>
+        <li>
+          <a href="receive-location-updates.html">Receiving Location Updates</a>
+        </li>
+      </ul>
+    <h2>Try it out</h2>
 
-<div class="download-box">
-<a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download
-  the sample app</a>
-<p class="filename">LocationUpdates.zip</p>
+    <ul>
+      <li>
+        <a href="https://github.com/googlesamples/android-play-location/tree/master/LocationAddress" class="external-link">LocationAddress</a>
+      </li>
+    </ul>
+  </div>
 </div>
 
-</div>
-</div>
+<p>The lessons <a href="retrieve-current.html">Getting the Last Known
+  Location</a> and <a href="receive-location-updates.html">Receiving Location
+  Updates</a> describe how to get the user's location in the form of a
+  {@link android.location.Location} object that contains latitude and longitude
+  coordinates. Although latitude and longitude are useful for calculating
+  distance or displaying a map position, in many cases the address of the
+  location is more useful. For example, if you want to let your users know where
+  they are or what is close by, a street address is more meaningful than the
+  geographic coordinates (latitude/longitude) of the location.</p>
+
+<p>Using the {@link android.location.Geocoder} class in the Android framework
+  location APIs, you can convert an address to the corresponding geographic
+  coordinates. This process is called <em>geocoding</em>. Alternatively, you can
+  convert a geographic location to an address. The address lookup feature is
+  also known as <em>reverse geocoding</em>.</p>
+
+<p>This lesson shows you how to use the
+  {@link android.location.Geocoder#getFromLocation getFromLocation()} method to
+  convert a geographic location to an address. The method returns an estimated
+  street address corresponding to a given latitude and longitude.</p>
+
+<h2 id="connect">Get a Geographic Location</h2>
+
+<p>The last known location of the device is a useful starting point for the
+  address lookup feature. The lesson on
+  <a href="retrieve-current.html">Getting the Last Known Location</a> shows you
+  how to use the
+  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>
+  method provided by the
+  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused
+  location provider</a> to find the latest location of the device.</p>
+
+<p>To access the fused location provider, you need to create an instance of the
+  Google Play services API client. To learn how to connect your client, see
+  <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
+  to Google Play Services</a>.</p>
+
+<p>In order for the fused location provider to retrieve a precise street
+  address, set the location permission in your app manifest to
+  {@code ACCESS_FINE_LOCATION}, as shown in the following example:</p>
 
-<p>
-    The lessons <a href="retrieve-current.html">Retrieving the Current Location</a> and
-    <a href="receive-location-updates.html">Receiving Location Updates</a> describe how to get the
-    user's current location in the form of a {@link android.location.Location} object that
-    contains latitude and longitude coordinates. Although latitude and longitude are useful for
-    calculating distance or displaying a map position, in many cases the address of the location is
-    more useful.
-</p>
-<p>
-    The Android platform API provides a feature that returns an estimated street addresses for
-    latitude and longitude values. This lesson shows you how to use this address lookup feature.
-</p>
-<p class="note">
-    <strong>Note:</strong> Address lookup requires a backend service that is not included in the
-    core Android framework. If this backend service is not available,
-    {@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()} returns an empty
-    list. The helper method {@link android.location.Geocoder#isPresent isPresent()}, available
-    in API level 9 and later, checks to see if the backend service is available.
-</p>
-<p>
-    The snippets in the following sections assume that your app has already retrieved the
-    current location and stored it as a {@link android.location.Location} object in the global
-    variable {@code mLocation}.
-</p>
-<!--
-    Define the address lookup task
--->
-<h2 id="DefineTask">Define the Address Lookup Task</h2>
-<p>
-To get an address for a given latitude and longitude, call
-{@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()}, which returns a
-list of addresses. The method is synchronous, and may take a long time to do its work, so you
-should call the method from the {@link android.os.AsyncTask#doInBackground
-doInBackground()} method of an {@link android.os.AsyncTask}.
-</p>
-<p>
-While your app is getting the address, display an indeterminate activity
-indicator to show that your app is working in the background. Set the indicator's initial state
-to {@code android:visibility="gone"}, to make it invisible and remove it from the layout
-hierarchy. When you start the address lookup, you set its visibility to "visible".
-</p>
-<p>
-The following snippet shows how to add an indeterminate {@link android.widget.ProgressBar} to
-your layout file:
-</p>
 <pre>
-&lt;ProgressBar
-android:id="&#64;+id/address_progress"
-android:layout_width="wrap_content"
-android:layout_height="wrap_content"
-android:layout_centerHorizontal="true"
-android:indeterminate="true"
-android:visibility="gone" /&gt;
+&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.gms.location.sample.locationupdates" &gt;
+
+  &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
+&lt;/manifest&gt;
 </pre>
-<p>
-To create the background task, define a subclass of {@link android.os.AsyncTask} that calls
-{@link android.location.Geocoder#getFromLocation getFromLocation()} and returns an address.
-Define a {@link android.widget.TextView} object {@code mAddress} to contain the returned
-address, and a {@link android.widget.ProgressBar} object that allows you to control the
-indeterminate activity indicator. For example:
-</p>
+
+<h2 id="fetch-address">Define an Intent Service to Fetch the Address</h2>
+
+<p>The {@link android.location.Geocoder#getFromLocation getFromLocation()}
+  method provided by the {@link android.location.Geocoder} class accepts a
+  latitude and longitude, and returns a list of addresses. The method is
+  synchronous, and may take a long time to do its work, so you should not call
+  it from the main, user interface (UI) thread of your app.</p>
+
+<p>The {@link android.app.IntentService IntentService} class provides a
+  structure for running a task on a background thread. Using this class, you can
+  handle a long-running operation without affecting your UI's responsiveness.
+  Note that the {@link android.os.AsyncTask AsyncTask} class also allows you to
+  perform background operations, but it's designed for short operations. An
+  {@link android.os.AsyncTask AsyncTask} shouldn't keep a reference to the UI if
+  the activity is recreated, for example when the device is rotated. In
+  contrast, an {@link android.app.IntentService IntentService} doesn't need to
+  be cancelled when the activity is rebuilt.</p>
+
+<p>Define a {@code FetchAddressIntentService} class that extends
+  {@link android.app.IntentService}. This class is your address lookup service.
+  The intent service handles an intent asynchronously on a worker thread, and
+  stops itself when it runs out of work. The intent extras provide the data
+  needed by the service, including a {@link android.location.Location} object
+  for conversion to an address, and a {@link android.os.ResultReceiver} object
+  to handle the results of the address lookup. The service uses a {@link
+  android.location.Geocoder} to fetch the address for the location, and sends
+  the results to the {@link android.os.ResultReceiver}.</p>
+
+<h3>Define the Intent Service in your App Manifest</h3>
+
+<p>Add an entry to your app manifest defining the intent service:</p>
+
 <pre>
-public class MainActivity extends FragmentActivity {
+&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.gms.location.sample.locationaddress" &gt;
+    &lt;application
+        ...
+        &lt;service
+            android:name=".FetchAddressIntentService"
+            android:exported="false"/&gt;
+    &lt;/application&gt;
     ...
-    private TextView mAddress;
-    private ProgressBar mActivityIndicator;
+&lt;/manifest&gt;
+</pre>
+
+<p class="note"><strong>Note:</strong> The {@code &lt;service&gt;} element in
+  the manifest doesn't need to include an intent filter, because your main
+  activity creates an explicit intent by specifying the name of the class to use
+  for the intent.</p>
+
+<h3>Create a Geocoder</h3>
+
+<p>The process of converting a geographic location to an address is called
+  <em>reverse geocoding</em>. To perform the main work of the intent service,
+  that is, your reverse geocoding request, implement
+  {@link android.app.IntentService#onHandleIntent onHandleIntent()} within the
+  {@code FetchAddressIntentService} class. Create a
+  {@link android.location.Geocoder} object to handle the reverse geocoding.</p>
+
+<p>A locale represents a specific geographical or linguistic region. Locale
+  objects are used to adjust the presentation of information, such as numbers or
+  dates, to suit the conventions in the region represented by the locale. Pass a
+  <a href="{@docRoot}reference/java/util/Locale.html">{@code Locale}</a> object
+  to the {@link android.location.Geocoder} object, to ensure that the resulting
+  address is localized to the user's geographic region.</p>
+
+<pre>
+&#64;Override
+protected void onHandleIntent(Intent intent) {
+    Geocoder geocoder = new Geocoder(this, Locale.getDefault());
     ...
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
+}
+</pre>
+
+<h3 id="retrieve-street-address">Retrieve the street address data</h3>
+
+<p>The next step is to retrieve the street address from the geocoder, handle
+  any errors that may occur, and send the results back to the activity that
+  requested the address. To report the results of the geocoding
+  process, you need two numeric constants that indicate success or failure.
+  Define a {@code Constants} class to contain the values, as shown in this code
+  snippet:</p>
+
+<pre>
+public final class Constants {
+    public static final int SUCCESS_RESULT = 0;
+    public static final int FAILURE_RESULT = 1;
+    public static final String PACKAGE_NAME =
+        "com.google.android.gms.location.sample.locationaddress";
+    public static final String RECEIVER = PACKAGE_NAME + ".RECEIVER";
+    public static final String RESULT_DATA_KEY = PACKAGE_NAME +
+        ".RESULT_DATA_KEY";
+    public static final String LOCATION_DATA_EXTRA = PACKAGE_NAME +
+        ".LOCATION_DATA_EXTRA";
+}
+</pre>
+
+<p>To get a street address corresponding to a geographical location, call
+  {@link android.location.Geocoder#getFromLocation getFromLocation()},
+  passing it the latitude and longitude from the location object, and the
+  maximum number of addresses you want returned. In this case, you want just one
+  address. The geocoder returns an array of addresses. If no addresses were
+  found to match the given location, it returns an empty list. If there is no
+  backend geocoding service available, the geocoder returns null.</p>
+
+<p>Check for the following errors as shown in the code sample below. If an error
+  occurs, place the corresponding error message in the {@code errorMessage}
+  variable, so you can send it back to the requesting activity:</p>
+
+<ul>
+  <li><strong>No location data provided</strong> - The intent extras do not
+    include the {@link android.location.Location} object required for reverse
+    geocoding.</li>
+  <li><strong>Invalid latitude or longitude used</strong> - The latitude
+    and/or longitude values provided in the {@link android.location.Location}
+    object are invalid.</li>
+  <li><strong>No geocoder available</strong> - The background geocoding service
+    is not available, due to a network error or IO exception.</li>
+  <li><strong>Sorry, no address found</strong> - The geocoder could not find an
+    address for the given latitude/longitude.</li>
+</ul>
+
+<p>To get the individual lines of an address object, use the
+  {@link android.location.Address#getAddressLine getAddressLine()}
+  method provided by the {@link android.location.Address} class. Then join the
+  lines into a list of address fragments ready to return to the activity that
+  requested the address.</p>
+
+<p>To send the results back to the requesting activity, call the
+  {@code deliverResultToReceiver()} method (defined in
+  <a href="#return-address">Return the address to the requestor</a>). The
+  results consist of the previously-mentioned numeric success/failure code and
+  a string. In the case of a successful reverse geocoding, the string contains
+  the address. In the case of a failure, the string contains the error message,
+  as shown in the code sample below:</p>
+
+<pre>
+&#64;Override
+protected void onHandleIntent(Intent intent) {
+    String errorMessage = "";
+
+    // Get the location passed to this service through an extra.
+    Location location = intent.getParcelableExtra(
+            Constants.LOCATION_DATA_EXTRA);
+
     ...
-    mAddress = (TextView) findViewById(R.id.address);
-    mActivityIndicator =
-            (ProgressBar) findViewById(R.id.address_progress);
+
+    List&lt;Address&gt; addresses = null;
+
+    try {
+        addresses = geocoder.getFromLocation(
+                location.getLatitude(),
+                location.getLongitude(),
+                // In this sample, get just a single address.
+                1);
+    } catch (IOException ioException) {
+        // Catch network or other I/O problems.
+        errorMessage = getString(R.string.service_not_available);
+        Log.e(TAG, errorMessage, ioException);
+    } catch (IllegalArgumentException illegalArgumentException) {
+        // Catch invalid latitude or longitude values.
+        errorMessage = getString(R.string.invalid_lat_long_used);
+        Log.e(TAG, errorMessage + ". " +
+                "Latitude = " + location.getLatitude() +
+                ", Longitude = " +
+                location.getLongitude(), illegalArgumentException);
     }
-    ...
-    /**
-    * A subclass of AsyncTask that calls getFromLocation() in the
-    * background. The class definition has these generic types:
-    * Location - A {@link android.location.Location} object containing
-    * the current location.
-    * Void     - indicates that progress units are not used
-    * String   - An address passed to onPostExecute()
-    */
-    private class GetAddressTask extends
-            AsyncTask&lt;Location, Void, String&gt; {
-        Context mContext;
-        public GetAddressTask(Context context) {
-            super();
-            mContext = context;
+
+    // Handle case where no address was found.
+    if (addresses == null || addresses.size()  == 0) {
+        if (errorMessage.isEmpty()) {
+            errorMessage = getString(R.string.no_address_found);
+            Log.e(TAG, errorMessage);
         }
-        ...
-        /**
-         * Get a Geocoder instance, get the latitude and longitude
-         * look up the address, and return it
-         *
-         * &#64;params params One or more Location objects
-         * &#64;return A string containing the address of the current
-         * location, or an empty string if no address can be found,
-         * or an error message
-         */
-        &#64;Override
-        protected String doInBackground(Location... params) {
-            Geocoder geocoder =
-                    new Geocoder(mContext, Locale.getDefault());
-            // Get the current location from the input parameter list
-            Location loc = params[0];
-            // Create a list to contain the result address
-            List&lt;Address&gt; addresses = null;
-            try {
-                /*
-                 * Return 1 address.
-                 */
-                addresses = geocoder.getFromLocation(loc.getLatitude(),
-                        loc.getLongitude(), 1);
-            } catch (IOException e1) {
-            Log.e("LocationSampleActivity",
-                    "IO Exception in getFromLocation()");
-            e1.printStackTrace();
-            return ("IO Exception trying to get address");
-            } catch (IllegalArgumentException e2) {
-            // Error message to post in the log
-            String errorString = "Illegal arguments " +
-                    Double.toString(loc.getLatitude()) +
-                    " , " +
-                    Double.toString(loc.getLongitude()) +
-                    " passed to address service";
-            Log.e("LocationSampleActivity", errorString);
-            e2.printStackTrace();
-            return errorString;
-            }
-            // If the reverse geocode returned an address
-            if (addresses != null &amp;&amp; addresses.size() &gt; 0) {
-                // Get the first address
-                Address address = addresses.get(0);
-                /*
-                 * Format the first line of address (if available),
-                 * city, and country name.
-                 */
-                String addressText = String.format(
-                        "&#037;s, &#037;s, &#037;s",
-                        // If there's a street address, add it
-                        address.getMaxAddressLineIndex() &gt; 0 ?
-                                address.getAddressLine(0) : "",
-                        // Locality is usually a city
-                        address.getLocality(),
-                        // The country of the address
-                        address.getCountryName());
-                // Return the text
-                return addressText;
-            } else {
-                return "No address found";
-            }
+        deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage);
+    } else {
+        Address address = addresses.get(0);
+        ArrayList&lt;String&gt; addressFragments = new ArrayList&lt;String&gt;();
+
+        // Fetch the address lines using {@code getAddressLine},
+        // join them, and send them to the thread.
+        for(int i = 0; i < address.getMaxAddressLineIndex(); i++) {
+            addressFragments.add(address.getAddressLine(i));
         }
-        ...
+        Log.i(TAG, getString(R.string.address_found));
+        deliverResultToReceiver(Constants.SUCCESS_RESULT,
+                TextUtils.join(System.getProperty("line.separator"),
+                        addressFragments));
     }
-    ...
 }
 </pre>
-<p>
-The next section shows you how to display the address in the user interface.
-</p>
-<!-- Define a method to display the address -->
-<h2 id="DisplayResults">Define a Method to Display the Results</h2>
-<p>
-    {@link android.os.AsyncTask#doInBackground doInBackground()} returns the result of the address
-    lookup as a {@link java.lang.String}. This value is passed to
-    {@link android.os.AsyncTask#onPostExecute onPostExecute()}, where you do further processing
-    on the results. Since {@link android.os.AsyncTask#onPostExecute onPostExecute()}
-    runs on the UI thread, it can update the user interface; for example, it can turn off the
-    activity indicator and display the results to the user:
+
+<h3 id="return-address">Return the address to the requestor</h3>
+
+<p>The final thing the intent service must do is send the address back to a
+  {@link android.os.ResultReceiver} in the activity that started the service.
+  The {@link android.os.ResultReceiver} class allows you to send a
+  numeric result code as well as a message containing the result data. The
+  numeric code is useful for reporting the success or failure of the geocoding
+  request. In the case of a successful reverse geocoding, the message contains
+  the address. In the case of a failure, the message contains some text
+  describing the reason for failure.</p>
+
+<p>You have already retrieved the address from the geocoder, trapped any errors
+  that may occur, and called the {@code deliverResultToReceiver()} method. Now
+  you need to define the {@code deliverResultToReceiver()} method that sends
+  a result code and message bundle to the result receiver.</p>
+
+<p>For the result code, use the value that you've passed to the
+  {@code deliverResultToReceiver()} method in the {@code resultCode} parameter.
+  To construct the message bundle, concatenate the {@code RESULT_DATA_KEY}
+  constant from your {@code Constants} class (defined in
+  <a href="#retrieve-street-address">Retrieve the street address data</a>) and
+  the value in the {@code message} parameter passed to the
+  {@code deliverResultToReceiver()} method, as shown in the following sample:
 </p>
+
 <pre>
-    private class GetAddressTask extends
-            AsyncTask&lt;Location, Void, String&gt; {
-        ...
-        /**
-         * A method that's called once doInBackground() completes. Turn
-         * off the indeterminate activity indicator and set
-         * the text of the UI element that shows the address. If the
-         * lookup failed, display the error message.
-         */
-        &#64;Override
-        protected void onPostExecute(String address) {
-            // Set activity indicator visibility to "gone"
-            mActivityIndicator.setVisibility(View.GONE);
-            // Display the results of the lookup.
-            mAddress.setText(address);
-        }
-        ...
+public class FetchAddressIntentService extends IntentService {
+    protected ResultReceiver mReceiver;
+    ...
+    private void deliverResultToReceiver(int resultCode, String message) {
+        Bundle bundle = new Bundle();
+        bundle.putString(Constants.RESULT_DATA_KEY, message);
+        mReceiver.send(resultCode, bundle);
     }
+}
 </pre>
-<p>
-    The final step is to run the address lookup.
-</p>
-<!-- Get and display the address -->
-<h2 id="RunTask">Run the Lookup Task</h2>
-<p>
-    To get the address, call {@link android.os.AsyncTask#execute execute()}. For example, the
-    following snippet starts the address lookup when the user clicks the "Get Address" button:
-</p>
+
+<h2 id="start-intent">Start the Intent Service</h2>
+
+<p>The intent service, as defined in the previous section, runs in the
+  background and is responsible for fetching the address corresponding to a
+  given geographic location. When you start the service, the Android framework
+  instantiates and starts the service if it isn't already running, and creates a
+  process if needed. If the service is already running then it remains running.
+  Because the service extends {@link android.app.IntentService IntentService},
+  it shuts down automatically when all intents have been processed.</p>
+  
+<p>Start the service from your app's main activity,
+  and create an {@link android.content.Intent} to pass data to the service. You
+  need an <em>explicit</em> intent, because you want only your service
+  to respond to the intent. For more information, see
+  <a href="{@docRoot}guide/components/intents-filters.html#Types">Intent
+  Types</a>.</p>
+
+<p>To create an explicit intent, specify the name of the
+  class to use for the service: {@code FetchAddressIntentService.class}.
+  Pass two pieces of information in the intent extras:</p>
+
+<ul>
+  <li>A {@link android.os.ResultReceiver} to handle the results of the address
+    lookup.</li>
+  <li>A {@link android.location.Location} object containing the latitude and
+    longitude that you want to convert to an address.</li>
+</ul>
+
+<p>The following code sample shows you how to start the intent service:</p>
+
 <pre>
-public class MainActivity extends FragmentActivity {
+public class MainActivity extends ActionBarActivity implements
+        ConnectionCallbacks, OnConnectionFailedListener {
+
+    protected Location mLastLocation;
+    private AddressResultReceiver mResultReceiver;
     ...
-    /**
-     * The "Get Address" button in the UI is defined with
-     * android:onClick="getAddress". The method is invoked whenever the
-     * user clicks the button.
-     *
-     * &#64;param v The view object associated with this method,
-     * in this case a Button.
-     */
-    public void getAddress(View v) {
-        // Ensure that a Geocoder services is available
-        if (Build.VERSION.SDK_INT &gt;=
-                Build.VERSION_CODES.GINGERBREAD
-                            &amp;&amp;
-                Geocoder.isPresent()) {
-            // Show the activity indicator
-            mActivityIndicator.setVisibility(View.VISIBLE);
-            /*
-             * Reverse geocoding is long-running and synchronous.
-             * Run it on a background thread.
-             * Pass the current location to the background task.
-             * When the task finishes,
-             * onPostExecute() displays the address.
-             */
-            (new GetAddressTask(this)).execute(mLocation);
+
+    protected void startIntentService() {
+        Intent intent = new Intent(this, FetchAddressIntentService.class);
+        intent.putExtra(Constants.RECEIVER, mResultReceiver);
+        intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
+        startService(intent);
+    }
+}
+</pre>
+
+<p>Call the above {@code startIntentService()} method when the
+  user takes an action that requires a geocoding address lookup. For example,
+  the user may press a <em>Fetch address</em> button on your app's UI. Before
+  starting the intent service, you need to check that the connection to Google
+  Play services is present. The following code snippet shows the call to the
+  {@code startIntentService()} method in the button handler:</p>
+
+<pre>
+public void fetchAddressButtonHandler(View view) {
+    // Only start the service to fetch the address if GoogleApiClient is
+    // connected.
+    if (mGoogleApiClient.isConnected() && mLastLocation != null) {
+        startIntentService();
+    }
+    // If GoogleApiClient isn't connected, process the user's request by
+    // setting mAddressRequested to true. Later, when GoogleApiClient connects,
+    // launch the service to fetch the address. As far as the user is
+    // concerned, pressing the Fetch Address button
+    // immediately kicks off the process of getting the address.
+    mAddressRequested = true;
+    updateUIWidgets();
+}
+</pre>
+
+<p>You must also start the intent service when the connection to Google Play
+  services is established, if the user has already clicked the button on your
+  app's UI. The following code snippet shows the call to the
+  {@code startIntentService()} method in the
+  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
+  callback provided by the Google API Client:</p>
+
+<pre>
+public class MainActivity extends ActionBarActivity implements
+        ConnectionCallbacks, OnConnectionFailedListener {
+    ...
+    &#64;Override
+    public void onConnected(Bundle connectionHint) {
+        // Gets the best and most recent location currently available,
+        // which may be null in rare cases when a location is not available.
+        mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
+                mGoogleApiClient);
+
+        if (mLastLocation != null) {
+            // Determine whether a Geocoder is available.
+            if (!Geocoder.isPresent()) {
+                Toast.makeText(this, R.string.no_geocoder_available,
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+
+            if (mAddressRequested) {
+                startIntentService();
+            }
         }
-        ...
     }
+}
+</pre>
+
+<h2 id="result-receiver">Receive the Geocoding Results</h2>
+
+<p>The intent service has handled the geocoding request, and uses a
+  {@link android.os.ResultReceiver} to return the results to the activity that
+  made the request. In the activity that makes the request, define an
+  {@code AddressResultReceiver} that extends {@link android.os.ResultReceiver}
+  to handle the response from {@code FetchAddressIntentService}.</p>
+
+<p>The result includes a numeric result code (<code>resultCode</code>) as well
+  as a message containing the result data (<code>resultData</code>). If the
+  reverse geocoding process was successful, the <code>resultData</code> contains
+  the address. In the case of a failure, the <code>resultData</code> contains
+  text describing the reason for failure. For details of the possible errors,
+  see <a href="#return-address">Return the address to the requestor</a>.</p>
+
+<p>Override the
+  {@link android.os.ResultReceiver#onReceiveResult onReceiveResult()} method
+  to handle the results delivered to the result receiver, as shown in the
+  following code sample:</p>
+
+<pre>
+public class MainActivity extends ActionBarActivity implements
+        ConnectionCallbacks, OnConnectionFailedListener {
     ...
+    class AddressResultReceiver extends ResultReceiver {
+        public AddressResultReceiver(Handler handler) {
+            super(handler);
+        }
+
+        &#64;Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+
+            // Display the address string
+            // or an error message sent from the intent service.
+            mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
+            displayAddressOutput();
+
+            // Show a toast message if an address was found.
+            if (resultCode == Constants.SUCCESS_RESULT) {
+                showToast(getString(R.string.address_found));
+            }
+
+        }
+    }
 }
 </pre>
-<p>
-    The next lesson, <a href="geofencing.html">Creating and Monitoring Geofences</a>, demonstrates
-    how to define locations of interest called <b>geofences</b> and how to use geofence monitoring
-    to detect the user's proximity to a location of interest.
-</p>
index 12babbf..49a8d32 100644 (file)
@@ -46,7 +46,7 @@ directly. Instead, you:
 </ol>
 
 <p>
-However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">setData()</a>,
+However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])"><code>setData()</code></a>,
 we recommend you <a href="#SyncData">use a data map</a>, which exposes
 a data item in an easy-to-use {@link android.os.Bundle}-like interface.
 </p>
@@ -88,39 +88,121 @@ app, you should create a path scheme that matches the structure of the data.
   </li>
 </ol>
 
-<p>The following example shows how to create a data map and put data on it:</p>
+<p>The <code>increaseCounter()</code> method in the following example shows how to create a
+data map and put data in it:</p>
 
 <pre>
-PutDataMapRequest dataMap = PutDataMapRequest.create("/count");
-dataMap.getDataMap().putInt(COUNT_KEY, count++);
-PutDataRequest request = dataMap.asPutDataRequest();
-PendingResult&lt;DataApi.DataItemResult&gt; pendingResult = Wearable.DataApi
-        .putDataItem(mGoogleApiClient, request);
+public class MainActivity extends Activity implements
+        DataApi.DataListener,
+        GoogleApiClient.ConnectionCallbacks,
+        GoogleApiClient.OnConnectionFailedListener {
+
+    private static final String COUNT_KEY = "com.example.key.count";
+
+    private GoogleApiClient mGoogleApiClient;
+    private int count = 0;
+
+    ...
+
+    // Create a data map and put data in it
+    private void <strong>increaseCounter</strong>() {
+        PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
+        putDataMapReq.getDataMap().putInt(COUNT_KEY, count++);
+        PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
+        PendingResult&lt;DataApi.DataItemResult> pendingResult =
+                Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
+    }
+
+    ...
+}
 </pre>
 
+<p>For more information about handling the
+<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">
+<code>PendingResult</code></a> object, see
+<a href="{@docRoot}training/wearables/data-layer/events.html#Wait">Wait for the Status of Data
+Layer Calls</a>.</p>
+
+
 <h2 id="ListenEvents">Listen for Data Item Events</h2>
-If one side of the data layer connection changes a data item, you probably want
+
+<p>If one side of the data layer connection changes a data item, you probably want
 to be notified of any changes on the other side of the connection.
-You can do this by implementing a listener for data item events.
+You can do this by implementing a listener for data item events.</p>
 
-<p>For example, here's what a typical callback looks like to carry out certain actions
-when data changes:</p>
+<p>The code snippet in the following example notifies your app when the value of the
+counter defined in the previous example changes:</p>
 
 <pre>
-&#64;Override
-public void onDataChanged(DataEventBuffer dataEvents) {
-    for (DataEvent event : dataEvents) {
-        if (event.getType() == DataEvent.TYPE_DELETED) {
-            Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
-        } else if (event.getType() == DataEvent.TYPE_CHANGED) {
-             Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
+public class MainActivity extends Activity implements
+        DataApi.DataListener,
+        GoogleApiClient.ConnectionCallbacks,
+        GoogleApiClient.OnConnectionFailedListener {
+
+    private static final String COUNT_KEY = "com.example.key.count";
+
+    private GoogleApiClient mGoogleApiClient;
+    private int count = 0;
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        mGoogleApiClient = new GoogleApiClient.Builder(this)
+                .addApi(Wearable.API)
+                .addConnectionCallbacks(this)
+                .addOnConnectionFailedListener(this)
+                .build();
+    }
+
+    &#64;Override
+    protected void onResume() {
+        super.onStart();
+        mGoogleApiClient.connect();
+    }
+
+    &#64;Override
+    public void onConnected(Bundle bundle) {
+        <strong>Wearable.DataApi.addListener</strong>(mGoogleApiClient, this);
+    }
+
+    &#64;Override
+    protected void onPause() {
+        super.onPause();
+        <strong>Wearable.DataApi.removeListener</strong>(mGoogleApiClient, this);
+        mGoogleApiClient.disconnect();
+    }
+
+    &#64;Override
+    public void <strong>onDataChanged</strong>(DataEventBuffer dataEvents) {
+        for (DataEvent event : dataEvents) {
+            if (event.getType() == DataEvent.TYPE_CHANGED) {
+                // DataItem changed
+                DataItem item = event.getDataItem();
+                if (item.getUri().getPath().compareTo("/count") == 0) {
+                    DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
+                    updateCount(dataMap.getInt(COUNT_KEY));
+                }
+            } else if (event.getType() == DataEvent.TYPE_DELETED) {
+                // DataItem deleted
+            }
         }
     }
+
+    // Our method to update the count
+    private void updateCount(int c) { ... }
+
+    ...
 }
 </pre>
-<p>
-This is just a snippet that requires more implementation details. Learn about
-how to implement a full listener service or activity in
+
+<p>This activity implements the
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html">
+<code>DataItem.DataListener</code></a> interface. This activity adds itself as a listener
+for data item events inside the <code>onConnected()</code> method and removes the listener
+in the <code>onPause()</code> method.</p>
+
+<p>You can also implement the listener as a service. For more information, see
 <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer
-Events</a>.
-</p>
\ No newline at end of file
+Events</a>.</p>
index 6a3949a..c797f68 100644 (file)
@@ -267,6 +267,8 @@ or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#rem
 public class MainActivity extends Activity implements
         DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {
 
+    private GoogleApiClient mGoogleApiClient;
+
     &#64;Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -314,4 +316,5 @@ public class MainActivity extends Activity implements
             }
         }
     }
+}
 </pre>
index 13cdc69..5d9355a 100755 (executable)
@@ -88,6 +88,10 @@ public class MtpDatabase {
             Files.FileColumns._ID, // 0
             Files.FileColumns.DATA, // 1
     };
+    private static final String[] FORMAT_PROJECTION = new String[] {
+            Files.FileColumns._ID, // 0
+            Files.FileColumns.FORMAT, // 1
+    };
     private static final String[] PATH_FORMAT_PROJECTION = new String[] {
             Files.FileColumns._ID, // 0
             Files.FileColumns.DATA, // 1
@@ -597,6 +601,7 @@ public class MtpDatabase {
             MtpConstants.PROPERTY_PARENT_OBJECT,
             MtpConstants.PROPERTY_PERSISTENT_UID,
             MtpConstants.PROPERTY_NAME,
+            MtpConstants.PROPERTY_DISPLAY_NAME,
             MtpConstants.PROPERTY_DATE_ADDED,
     };
 
@@ -669,43 +674,6 @@ public class MtpDatabase {
             MtpConstants.PROPERTY_DESCRIPTION,
     };
 
-    static final int[] ALL_PROPERTIES = {
-            // NOTE must match FILE_PROPERTIES above
-            MtpConstants.PROPERTY_STORAGE_ID,
-            MtpConstants.PROPERTY_OBJECT_FORMAT,
-            MtpConstants.PROPERTY_PROTECTION_STATUS,
-            MtpConstants.PROPERTY_OBJECT_SIZE,
-            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
-            MtpConstants.PROPERTY_DATE_MODIFIED,
-            MtpConstants.PROPERTY_PARENT_OBJECT,
-            MtpConstants.PROPERTY_PERSISTENT_UID,
-            MtpConstants.PROPERTY_NAME,
-            MtpConstants.PROPERTY_DISPLAY_NAME,
-            MtpConstants.PROPERTY_DATE_ADDED,
-
-            // image specific properties
-            MtpConstants.PROPERTY_DESCRIPTION,
-
-            // audio specific properties
-            MtpConstants.PROPERTY_ARTIST,
-            MtpConstants.PROPERTY_ALBUM_NAME,
-            MtpConstants.PROPERTY_ALBUM_ARTIST,
-            MtpConstants.PROPERTY_TRACK,
-            MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
-            MtpConstants.PROPERTY_DURATION,
-            MtpConstants.PROPERTY_GENRE,
-            MtpConstants.PROPERTY_COMPOSER,
-
-            // video specific properties
-            MtpConstants.PROPERTY_ARTIST,
-            MtpConstants.PROPERTY_ALBUM_NAME,
-            MtpConstants.PROPERTY_DURATION,
-            MtpConstants.PROPERTY_DESCRIPTION,
-
-            // image specific properties
-            MtpConstants.PROPERTY_DESCRIPTION,
-    };
-
     private int[] getSupportedObjectProperties(int format) {
         switch (format) {
             case MtpConstants.FORMAT_MP3:
@@ -723,8 +691,6 @@ public class MtpDatabase {
             case MtpConstants.FORMAT_PNG:
             case MtpConstants.FORMAT_BMP:
                 return IMAGE_PROPERTIES;
-            case 0:
-                return ALL_PROPERTIES;
             default:
                 return FILE_PROPERTIES;
         }
@@ -749,6 +715,10 @@ public class MtpDatabase {
 
         MtpPropertyGroup propertyGroup;
         if (property == 0xFFFFFFFFL) {
+            if (format == 0 && handle > 0) {
+                // return properties based on the object's format
+                format = getObjectFormat((int)handle);
+            }
              propertyGroup = mPropertyGroupsByFormat.get(format);
              if (propertyGroup == null) {
                 int[] propertyList = getSupportedObjectProperties(format);
@@ -988,6 +958,26 @@ public class MtpDatabase {
         }
     }
 
+    private int getObjectFormat(int handle) {
+        Cursor c = null;
+        try {
+            c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION,
+                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
+            if (c != null && c.moveToNext()) {
+                return c.getInt(1);
+            } else {
+                return -1;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getObjectFilePath", e);
+            return -1;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
     private int deleteFile(int handle) {
         mDatabaseModified = true;
         String path = null;
index 781988d..c80adfa 100644 (file)
@@ -172,6 +172,17 @@ class MtpPropertyGroup {
                 column = Images.ImageColumns.DESCRIPTION;
                 type = MtpConstants.TYPE_STR;
                 break;
+            case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
+            case MtpConstants.PROPERTY_AUDIO_BITRATE:
+            case MtpConstants.PROPERTY_SAMPLE_RATE:
+                // these are special cased
+                type = MtpConstants.TYPE_UINT32;
+                break;
+            case MtpConstants.PROPERTY_BITRATE_TYPE:
+            case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
+                // these are special cased
+                type = MtpConstants.TYPE_UINT16;
+                break;
             default:
                 type = MtpConstants.TYPE_UNDEFINED;
                 Log.e(TAG, "unsupported property " + code);
@@ -420,6 +431,17 @@ class MtpPropertyGroup {
                                 result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
                             }
                             break;
+                        case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
+                        case MtpConstants.PROPERTY_AUDIO_BITRATE:
+                        case MtpConstants.PROPERTY_SAMPLE_RATE:
+                            // we don't have these in our database, so return 0
+                            result.append(handle, propertyCode, MtpConstants.TYPE_UINT32, 0);
+                            break;
+                        case MtpConstants.PROPERTY_BITRATE_TYPE:
+                        case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
+                            // we don't have these in our database, so return 0
+                            result.append(handle, propertyCode, MtpConstants.TYPE_UINT16, 0);
+                            break;
                         default:
                             if (property.type == MtpConstants.TYPE_STR) {
                                 result.append(handle, propertyCode, c.getString(column));
index b8e850a..8b2e203 100644 (file)
@@ -930,6 +930,11 @@ static const PropertyTableEntry   kObjectPropertyTable[] = {
     {   MTP_PROPERTY_COMPOSER,          MTP_TYPE_STR        },
     {   MTP_PROPERTY_DURATION,          MTP_TYPE_UINT32     },
     {   MTP_PROPERTY_DESCRIPTION,       MTP_TYPE_STR        },
+    {   MTP_PROPERTY_AUDIO_WAVE_CODEC,  MTP_TYPE_UINT32     },
+    {   MTP_PROPERTY_BITRATE_TYPE,      MTP_TYPE_UINT16     },
+    {   MTP_PROPERTY_AUDIO_BITRATE,     MTP_TYPE_UINT32     },
+    {   MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_TYPE_UINT16     },
+    {   MTP_PROPERTY_SAMPLE_RATE,       MTP_TYPE_UINT32     },
 };
 
 static const PropertyTableEntry   kDevicePropertyTable[] = {
diff --git a/packages/PrintSpooler/res/values-ca/arrays.xml b/packages/PrintSpooler/res/values-ca/arrays.xml
new file mode 100644 (file)
index 0000000..c1b149c
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>NA_LETTER</item>
+        <item>NA_GOVT_LETTER</item>
+        <item>NA_LEGAL</item>
+        <item>NA_JUNIOR_LEGAL</item>
+        <item>NA_LEDGER</item>
+        <item>NA_TABLOID</item>
+        <item>NA_INDEX_3X5</item>
+        <item>NA_INDEX_4X6</item>
+        <item>NA_INDEX_5X8</item>
+        <item>NA_MONARCH</item>
+        <item>NA_QUARTO</item>
+        <item>NA_FOOLSCAP</item>
+    </string-array>
+
+</resources>
index 1f98670..281fde3 100644 (file)
@@ -894,7 +894,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
     }
 
     void doInvalidatePanelMenu(int featureId) {
-        PanelFeatureState st = getPanelState(featureId, true);
+        PanelFeatureState st = getPanelState(featureId, false);
+        if (st == null) {
+            return;
+        }
         Bundle savedActionViewStates = null;
         if (st.menu != null) {
             savedActionViewStates = new Bundle();
@@ -933,8 +936,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
             // The panel key was pushed, so set the chording key
             mPanelChordingKey = keyCode;
 
-            PanelFeatureState st = getPanelState(featureId, true);
-            if (!st.isOpen) {
+            PanelFeatureState st = getPanelState(featureId, false);
+            if (st != null && !st.isOpen) {
                 return preparePanel(st, event);
             }
         }
@@ -952,12 +955,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
         if (mPanelChordingKey != 0) {
             mPanelChordingKey = 0;
 
-            if (event.isCanceled() || (mDecor != null && mDecor.mActionMode != null)) {
+            final PanelFeatureState st = getPanelState(featureId, false);
+
+            if (event.isCanceled() || (mDecor != null && mDecor.mActionMode != null) ||
+                    (st == null)) {
                 return;
             }
 
             boolean playSoundEffect = false;
-            final PanelFeatureState st = getPanelState(featureId, true);
             if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
                     mDecorContentParent.canShowOverflowMenu() &&
                     !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
@@ -1056,7 +1061,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
 
     @Override
     public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
-        return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags);
+        return performPanelShortcut(getPanelState(featureId, false), keyCode, event, flags);
     }
 
     private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
@@ -1149,11 +1154,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
                         mInvalidatePanelMenuRunnable.run();
                     }
 
-                    final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+                    final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
 
                     // If we don't have a menu or we're waiting for a full content refresh,
                     // forget it. This is a lingering event that no longer matters.
-                    if (st.menu != null && !st.refreshMenuContent &&
+                    if (st != null && st.menu != null && !st.refreshMenuContent &&
                             cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
                         cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
                         mDecorContentParent.showOverflowMenu();
@@ -1161,15 +1166,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
                 }
             } else {
                 mDecorContentParent.hideOverflowMenu();
-                if (cb != null && !isDestroyed()) {
-                    final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+                final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+                if (st != null && cb != null && !isDestroyed()) {
                     cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
                 }
             }
             return;
         }
 
-        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+
+        if (st == null) {
+            return;
+        }
 
         // Save the future expanded mode state since closePanel will reset it
         boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
@@ -2302,8 +2311,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
             // combination such as Control+C.  Temporarily prepare the panel then mark it
             // unprepared again when finished to ensure that the panel will again be prepared
             // the next time it is shown for real.
-            if (mPreparedPanel == null) {
-                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+            if (st != null && mPreparedPanel == null) {
                 preparePanel(st, ev);
                 handled = performPanelShortcut(st, ev.getKeyCode(), ev,
                         Menu.FLAG_PERFORM_NO_CLOSE);
@@ -3906,8 +3915,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
 
     @Override
     public boolean isShortcutKey(int keyCode, KeyEvent event) {
-        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
-        return st.menu != null && st.menu.isShortcutKey(keyCode, event);
+        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+        return st != null && st.menu != null && st.menu.isShortcutKey(keyCode, event);
     }
 
     private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) {
index 6d28382..aefbf60 100755 (executable)
@@ -72,7 +72,7 @@ public final class ActiveServices {
     static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
     static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
     static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
-    static final boolean LOG_SERVICE_START_STOP = true;
+    static final boolean LOG_SERVICE_START_STOP = false;
     static final String TAG = ActivityManagerService.TAG;
     static final String TAG_MU = ActivityManagerService.TAG_MU;
 
index 40bcf8e..e8f3757 100755 (executable)
@@ -2358,7 +2358,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         return mAppBindArgs;
     }
 
-    final void setFocusedActivityLocked(ActivityRecord r) {
+    final void setFocusedActivityLocked(ActivityRecord r, String reason) {
         if (mFocusedActivity != r) {
             if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
             mFocusedActivity = r;
@@ -2367,7 +2367,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             } else {
                 finishRunningVoiceLocked();
             }
-            mStackSupervisor.setFocusedStack(r);
+            mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity");
             if (r != null) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
@@ -2391,7 +2391,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             if (stack != null) {
                 ActivityRecord r = stack.topRunningActivityLocked(null);
                 if (r != null) {
-                    setFocusedActivityLocked(r);
+                    setFocusedActivityLocked(r, "setFocusedStack");
                 }
             }
         }
@@ -2435,7 +2435,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         mHandler.sendMessage(msg);
     }
 
-    private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
+    private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
             String what, Object obj, ProcessRecord srcApp) {
         app.lastActivityTime = now;
 
@@ -3109,7 +3109,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         return intent;
     }
 
-    boolean startHomeActivityLocked(int userId) {
+    boolean startHomeActivityLocked(int userId, String reason) {
         if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                 && mTopAction == null) {
             // We are running in factory test mode, but unable to find
@@ -3131,7 +3131,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     aInfo.applicationInfo.uid, true);
             if (app == null || app.instrumentationClass == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mStackSupervisor.startHomeActivity(intent, aInfo);
+                mStackSupervisor.startHomeActivity(intent, aInfo, reason);
             }
         }
 
@@ -6203,7 +6203,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     startProcessLocked(procs.get(ip), "on-hold", null);
                 }
             }
-            
+
             if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 // Start looking for apps that are abusing wake locks.
                 Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
@@ -6343,7 +6343,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                stack.activityDestroyedLocked(token);
+                stack.activityDestroyedLocked(token, "activityDestroyed");
             }
         }
     }
@@ -6454,7 +6454,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 throw new IllegalArgumentException("File descriptors passed in options");
             }
         }
-        
+
         synchronized(this) {
             int callingUid = Binder.getCallingUid();
             int origUserId = userId;
@@ -6484,7 +6484,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
                 return getIntentSenderLocked(type, packageName, callingUid, userId,
                         token, resultWho, requestCode, intents, resolvedTypes, flags, options);
-                
+
             } catch (RemoteException e) {
                 throw new SecurityException(e);
             }
@@ -8536,7 +8536,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             if (prev != null && prev.isRecentsActivity()) {
                 task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
             }
-            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options);
+            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront");
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -8565,7 +8565,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 }
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    stack.moveTaskToBackLocked(taskId, null);
+                    stack.moveTaskToBackLocked(taskId);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -8595,7 +8595,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                         mStackSupervisor.showLockTaskToast();
                         return false;
                     }
-                    return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId, null);
+                    return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
                 }
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -8687,7 +8687,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             try {
                 if (DEBUG_STACK) Slog.d(TAG, "moveTaskToStack: moving task=" + taskId + " to stackId="
                         + stackId + " toTop=" + toTop);
-                mStackSupervisor.moveTaskToStack(taskId, stackId, toTop);
+                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -8793,7 +8793,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                                     || (task != mStackSupervisor.getFocusedStack().topTask()))) {
                         throw new IllegalArgumentException("Invalid task, not in foreground");
                     }
-                    mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated);
+                    mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,
+                            "startLockTask");
                 }
             }
         } finally {
@@ -8878,7 +8879,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             Log.d(TAG, "stopLockTaskMode");
             // Stop lock task
             synchronized (this) {
-                mStackSupervisor.setLockTaskModeLocked(null, false);
+                mStackSupervisor.setLockTaskModeLocked(null, false, "stopLockTask");
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -11338,7 +11339,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
             // Start up initial activity.
             mBooting = true;
-            startHomeActivityLocked(mCurrentUserId);
+            startHomeActivityLocked(mCurrentUserId, "systemReady");
 
             try {
                 if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
@@ -18885,7 +18886,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     return true;
                 }
 
-                mStackSupervisor.setLockTaskModeLocked(null, false);
+                mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
 
                 final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                 if (userInfo == null) {
@@ -19142,7 +19143,7 @@ public final class ActivityManagerService extends ActivityManagerNative
     void moveUserToForeground(UserStartedState uss, int oldUserId, int newUserId) {
         boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
         if (homeInFront) {
-            startHomeActivityLocked(newUserId);
+            startHomeActivityLocked(newUserId, "moveUserToFroreground");
         } else {
             mStackSupervisor.resumeTopActivitiesLocked();
         }
index 0b49c9c..b1b2a5c 100755 (executable)
@@ -516,7 +516,7 @@ final class ActivityRecord {
     void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
         if (task != null && task.removeActivity(this)) {
             if (task != newTask) {
-                task.stack.removeTask(task);
+                task.stack.removeTask(task, "setTask");
             } else {
                 Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
                         (newTask == null ? null : newTask.stack));
index 4e932c1..6497cd7 100755 (executable)
@@ -291,7 +291,7 @@ final class ActivityStack {
                     // so we need to be conservative and assume it isn't.
                     Slog.w(TAG, "Activity destroy timeout for " + r);
                     synchronized (mService) {
-                        activityDestroyedLocked(r != null ? r.appToken : null);
+                        activityDestroyedLocked(r != null ? r.appToken : null, "destroyTimeout");
                     }
                 } break;
                 case STOP_TIMEOUT_MSG: {
@@ -473,10 +473,10 @@ final class ActivityStack {
                 mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
     }
 
-    final void moveToFront() {
+    final void moveToFront(String reason) {
         if (isAttached()) {
             if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(isHomeStack());
+                mStackSupervisor.moveHomeStack(isHomeStack(), reason);
             }
             mStacks.remove(this);
             mStacks.add(this);
@@ -1496,7 +1496,7 @@ final class ActivityStack {
             final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                     HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
             return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
+                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");
         }
 
         next.delayedResume = false;
@@ -1532,7 +1532,7 @@ final class ActivityStack {
                         "resumeTopActivityLocked: Launching home next");
                 final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                         HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
-                return mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
+                return mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");
             }
         }
 
@@ -1817,11 +1817,8 @@ final class ActivityStack {
                     next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
                 }
 
-                EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
-                        next.userId, System.identityHashCode(next),
-                        next.task.taskId, next.shortComponentName + " top="
-                                + mStacks.get(mStacks.size() - 1).mStackId + " Callers="
-                                + Debug.getCallers(6));
+                EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
+                        System.identityHashCode(next), next.task.taskId, next.shortComponentName);
 
                 next.sleeping = false;
                 mService.showAskCompatModeDialogLocked(next);
@@ -2468,18 +2465,19 @@ final class ActivityStack {
         r.addResultLocked(null, resultWho, requestCode, resultCode, data);
     }
 
-    private void adjustFocusedActivityLocked(ActivityRecord r) {
+    private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
         if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) {
             ActivityRecord next = topRunningActivityLocked(null);
             if (next != r) {
                 final TaskRecord task = r.task;
                 if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
+                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(),
+                            reason + " adjustFocus");
                 }
             }
             ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
             if (top != null) {
-                mService.setFocusedActivityLocked(top);
+                mService.setFocusedActivityLocked(top, reason + " adjustTopFocus");
             }
         }
     }
@@ -2503,7 +2501,7 @@ final class ActivityStack {
         }
 
         if (r.app != null && r.app.thread != null) {
-            adjustFocusedActivityLocked(r);
+            adjustFocusedActivityLocked(r, "stopActivity");
             r.resumeKeyDispatchingLocked();
             try {
                 r.stopped = false;
@@ -2707,7 +2705,7 @@ final class ActivityStack {
 
         r.pauseKeyDispatchingLocked();
 
-        adjustFocusedActivityLocked(r);
+        adjustFocusedActivityLocked(r, "finishActivity");
 
         finishActivityResultsLocked(r, resultCode, resultData);
 
@@ -3010,7 +3008,7 @@ final class ActivityStack {
         r.finishLaunchTickingLocked();
     }
 
-    private void removeActivityFromHistoryLocked(ActivityRecord r) {
+    private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
         mStackSupervisor.removeChildActivityContainers(r);
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
         r.makeFinishing();
@@ -3035,9 +3033,9 @@ final class ActivityStack {
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
             if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
-                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
+                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), reason);
             }
-            removeTask(task);
+            removeTask(task, reason);
         }
         cleanUpActivityServicesLocked(r);
         r.removeUriPermissionsLocked();
@@ -3202,7 +3200,7 @@ final class ActivityStack {
                 // up.
                 //Slog.w(TAG, "Exception thrown during finish", e);
                 if (r.finishing) {
-                    removeActivityFromHistoryLocked(r);
+                    removeActivityFromHistoryLocked(r, reason + " exceptionInScheduleDestroy");
                     removedFromHistory = true;
                     skipDestroy = true;
                 }
@@ -3232,7 +3230,7 @@ final class ActivityStack {
         } else {
             // remove this record from the history.
             if (r.finishing) {
-                removeActivityFromHistoryLocked(r);
+                removeActivityFromHistoryLocked(r, reason + " hadNoApp");
                 removedFromHistory = true;
             } else {
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (no app)");
@@ -3251,7 +3249,7 @@ final class ActivityStack {
         return removedFromHistory;
     }
 
-    final void activityDestroyedLocked(IBinder token) {
+    final void activityDestroyedLocked(IBinder token, String reason) {
         final long origId = Binder.clearCallingIdentity();
         try {
             ActivityRecord r = ActivityRecord.forToken(token);
@@ -3263,7 +3261,7 @@ final class ActivityStack {
             if (isInStackLocked(token) != null) {
                 if (r.state == ActivityState.DESTROYING) {
                     cleanUpActivityLocked(r, true, false);
-                    removeActivityFromHistoryLocked(r);
+                    removeActivityFromHistoryLocked(r, reason);
                 }
             }
             mStackSupervisor.resumeTopActivitiesLocked();
@@ -3399,7 +3397,7 @@ final class ActivityStack {
                                 mService.updateUsageStats(r, false);
                             }
                         }
-                        removeActivityFromHistoryLocked(r);
+                        removeActivityFromHistoryLocked(r, "appDied");
 
                     } else {
                         // We have the current state for this activity, so
@@ -3468,15 +3466,16 @@ final class ActivityStack {
         }
     }
 
-    final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
+    final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord source, Bundle options,
+            String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
         final int numTasks = mTaskHistory.size();
         final int index = mTaskHistory.indexOf(tr);
         if (numTasks == 0 || index < 0)  {
             // nothing to do!
-            if (reason != null &&
-                    (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            if (source != null &&
+                    (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                 ActivityOptions.abort(options);
             } else {
                 updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
@@ -3487,11 +3486,11 @@ final class ActivityStack {
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
         insertTaskAtTop(tr);
-        moveToFront();
+        moveToFront(reason);
 
         if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
-        if (reason != null &&
-                (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+        if (source != null &&
+                (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
@@ -3521,7 +3520,7 @@ final class ActivityStack {
      * @param taskId The taskId to collect and move to the bottom.
      * @return Returns true if the move completed, false if not.
      */
-    final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+    final boolean moveTaskToBackLocked(int taskId) {
         final TaskRecord tr = taskForIdLocked(taskId);
         if (tr == null) {
             Slog.i(TAG, "moveTaskToBack: bad taskId=" + taskId);
@@ -3576,16 +3575,7 @@ final class ActivityStack {
             }
         }
 
-        if (reason != null &&
-                (reason.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
-            ActivityRecord r = topRunningActivityLocked(null);
-            if (r != null) {
-                mNoAnimActivities.add(r);
-            }
-        } else {
-            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
-        }
+        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
         mWindowManager.moveTaskToBottom(taskId);
 
         if (VALIDATE_TOKENS) {
@@ -3600,7 +3590,7 @@ final class ActivityStack {
             }
             final int taskToReturnTo = tr.getTaskToReturnTo();
             tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null);
+            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
         }
 
         mStackSupervisor.resumeTopActivitiesLocked();
@@ -4042,7 +4032,7 @@ final class ActivityStack {
         return starting;
     }
 
-    void removeTask(TaskRecord task) {
+    void removeTask(TaskRecord task, String reason) {
         mStackSupervisor.endLockTaskModeIfTaskEnding(task);
         mWindowManager.removeTask(task.taskId);
         final ActivityRecord r = mResumedActivity;
@@ -4080,7 +4070,7 @@ final class ActivityStack {
         if (mTaskHistory.isEmpty()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
             if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(!isHomeStack());
+                mStackSupervisor.moveHomeStack(!isHomeStack(), reason + " leftTaskHistoryEmpty");
             }
             if (mStacks != null) {
                 mStacks.remove(this);
index 5c8e191..32787d8 100644 (file)
@@ -398,7 +398,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return false;
     }
 
-    void moveHomeStack(boolean toFront) {
+    void moveHomeStack(boolean toFront, String reason) {
         ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         final int topNdx = stacks.size() - 1;
         if (topNdx <= 0) {
@@ -416,7 +416,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         }
         EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
                 mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
-                mFocusedStack == null ? -1 : mFocusedStack.getStackId());
+                mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
 
         if (mService.mBooting || !mService.mBooted) {
             final ActivityRecord r = topRunningActivityLocked();
@@ -426,16 +426,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
         }
     }
 
-    void moveHomeStackTaskToTop(int homeStackTaskType) {
+    void moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
         if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
             mWindowManager.showRecentApps();
             return;
         }
-        moveHomeStack(true);
+        moveHomeStack(true, reason);
         mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
     }
 
-    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev) {
+    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
             return false;
@@ -445,7 +445,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             mWindowManager.showRecentApps();
             return false;
         }
-        moveHomeStackTaskToTop(homeStackTaskType);
+        moveHomeStackTaskToTop(homeStackTaskType, reason);
         if (prev != null) {
             prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
         }
@@ -453,10 +453,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
         // if (r != null && (r.isHomeActivity() || r.isRecentsActivity())) {
         if (r != null && r.isHomeActivity()) {
-            mService.setFocusedActivityLocked(r);
+            mService.setFocusedActivityLocked(r, reason);
             return resumeTopActivitiesLocked(mHomeStack, prev, null);
         }
-        return mService.startHomeActivityLocked(mCurrentUser);
+        return mService.startHomeActivityLocked(mCurrentUser, reason);
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
@@ -828,8 +828,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return aInfo;
     }
 
-    void startHomeActivity(Intent intent, ActivityInfo aInfo) {
-        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE);
+    void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
+        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
         startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null,
                 0, 0, 0, null, false, null, null, null);
     }
@@ -1581,7 +1581,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return mHomeStack;
     }
 
-    void setFocusedStack(ActivityRecord r) {
+    void setFocusedStack(ActivityRecord r, String reason) {
         if (r != null) {
             final TaskRecord task = r.task;
             boolean isHomeActivity = !r.isApplicationActivity();
@@ -1592,7 +1592,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
                 isHomeActivity = parent != null && parent.isHomeActivity();
             }
-            moveHomeStack(isHomeActivity);
+            moveHomeStack(isHomeActivity, reason);
         }
     }
 
@@ -1840,7 +1840,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                     targetStack.mLastPausedActivity = null;
                     if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
                             + " from " + intentActivity);
-                    targetStack.moveToFront();
+                    targetStack.moveToFront("intentActivityFound");
                     if (intentActivity.task.intent == null) {
                         // This task was started because of movement of
                         // the activity based on affinity...  now that we
@@ -1869,7 +1869,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
                                 intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                             }
                             movedHome = true;
-                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
+                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options,
+                                    "bringingFoundTaskToFront");
                             if ((launchFlags &
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
@@ -2067,7 +2068,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             newTask = true;
             targetStack = adjustStackFocus(r, newTask);
             if (!launchTaskBehind) {
-                targetStack.moveToFront();
+                targetStack.moveToFront("startingNewTask");
             }
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
@@ -2096,10 +2097,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             targetStack = sourceTask.stack;
-            targetStack.moveToFront();
+            targetStack.moveToFront("sourceStackToFront");
             final TaskRecord topTask = targetStack.topTask();
             if (topTask != sourceTask) {
-                targetStack.moveTaskToFrontLocked(sourceTask, r, options);
+                targetStack.moveTaskToFrontLocked(sourceTask, r, options, "sourceTaskToFront");
             }
             if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                 // In this case, we are adding the activity to an existing
@@ -2153,7 +2154,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             targetStack = inTask.stack;
-            targetStack.moveTaskToFrontLocked(inTask, r, options);
+            targetStack.moveTaskToFrontLocked(inTask, r, options, "inTaskToFront");
 
             // Check whether we should actually launch the new activity in to the task,
             // or just reuse the current activity on top.
@@ -2189,7 +2190,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
             targetStack = adjustStackFocus(r, newTask);
-            targetStack.moveToFront();
+            targetStack.moveToFront("addingToTopTask");
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                             r.info, intent, null, null, true), null);
@@ -2212,7 +2213,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
         if (!launchTaskBehind) {
             // Don't set focus on an activity that's going to the back.
-            mService.setFocusedActivityLocked(r);
+            mService.setFocusedActivityLocked(r, "startedActivity");
         }
         return ActivityManager.START_SUCCESS;
     }
@@ -2509,7 +2510,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         }
     }
 
-    void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options) {
+    void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options, String reason) {
         if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
             mUserLeaving = true;
         }
@@ -2518,7 +2519,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             // we'll just indicate that this task returns to the home task.
             task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
         }
-        task.stack.moveTaskToFrontLocked(task, null, options);
+        task.stack.moveTaskToFrontLocked(task, null, options, reason);
         if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
                 + task.stack);
     }
@@ -2643,7 +2644,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             // display.
             stack = getStack(createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY));
             // Restore home stack to top.
-            moveHomeStack(true);
+            moveHomeStack(true, "restoreRecentTask");
             if (DEBUG_RECENTS)
                 Slog.v(TAG, "Created stack=" + stack + " for recents restoration.");
         }
@@ -2670,7 +2671,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return true;
     }
 
-    void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             return;
@@ -2680,7 +2681,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        task.stack.removeTask(task);
+        task.stack.removeTask(task, "moveTaskToStack");
         stack.addTask(task, toTop, true);
         mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
@@ -3046,14 +3047,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
         }
         final boolean homeInFront = stack.isHomeStack();
         if (stack.isOnHomeDisplay()) {
-            moveHomeStack(homeInFront);
+            moveHomeStack(homeInFront, "switchUserOnHomeDisplay");
             TaskRecord task = stack.topTask();
             if (task != null) {
                 mWindowManager.moveTaskToTop(task.taskId);
             }
         } else {
             // Stack was moved to another display while user was swapped out.
-            resumeHomeStackTask(HOME_ACTIVITY_TYPE, null);
+            resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay");
         }
         return homeInFront;
     }
@@ -3454,7 +3455,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         mLockTaskNotify.showToast(mLockTaskIsLocked);
     }
 
-    void setLockTaskModeLocked(TaskRecord task, boolean isLocked) {
+    void setLockTaskModeLocked(TaskRecord task, boolean isLocked, String reason) {
         if (task == null) {
             // Take out of lock task mode if necessary
             if (mLockTaskModeTask != null) {
@@ -3471,7 +3472,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             return;
         }
         mLockTaskModeTask = task;
-        findTaskToMoveToFrontLocked(task, 0, null);
+        findTaskToMoveToFrontLocked(task, 0, null, reason);
         resumeTopActivitiesLocked();
 
         final Message lockTaskMsg = Message.obtain();
index 41499be..c376744 100644 (file)
@@ -94,4 +94,4 @@ option java_package com.android.server.am
 30043 am_focused_activity (User|1|5),(Component Name|3)
 
 # Home Stack brought to front or rear
-30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5)
+30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3)
index 2af56fe..50b2262 100644 (file)
@@ -677,7 +677,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
         private AudioDevicePort mAudioSource;
         private List<AudioDevicePort> mAudioSink = new ArrayList<>();
         private AudioPatch mAudioPatch = null;
-        private float mCommittedVolume = 0.0f;
+        // Set to an invalid value for a volume, so that current volume can be applied at the
+        // first call to updateAudioConfigLocked().
+        private float mCommittedVolume = -1f;
         private float mSourceVolume = 0.0f;
 
         private TvStreamConfig mActiveConfig = null;
index 2ca5629..fd4c016 100644 (file)
@@ -4734,6 +4734,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     public UserHandle createAndInitializeUser(ComponentName who, String name,
             String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
         UserHandle user = createUser(who, name);
+        if (user == null) {
+            return null;
+        }
         long id = Binder.clearCallingIdentity();
         try {
             String profileOwnerPkg = profileOwnerComponent.getPackageName();
@@ -4893,6 +4896,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                     }
                 }
                 mUserManager.setUserRestriction(key, enabled, user);
+                if (enabled != alreadyRestricted) {
+                    if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
+                        // Send out notifications however as some clients may want to reread the
+                        // value which actually changed due to a restriction having been applied.
+                        final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+                        long version = SystemProperties.getLong(property, 0) + 1;
+                        SystemProperties.set(property, Long.toString(version));
+
+                        final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
+                        Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+                        mContext.getContentResolver().notifyChange(url, null, true, userHandle);
+                    }
+                }
             } finally {
                 restoreCallingIdentity(id);
             }
index 6621726..1a6b292 100644 (file)
@@ -691,7 +691,7 @@ public class TelecomManager {
                 getTelecomService().clearAccounts(packageName);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#clearAccountsForPackage()", e);
+            Log.e(TAG, "Error calling ITelecomService#clearAccountsForPackage", e);
         }
     }
 
@@ -726,7 +726,7 @@ public class TelecomManager {
                 return getTelecomService().isVoiceMailNumber(accountHandle, number);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException calling isInCall().", e);
+            Log.e(TAG, "RemoteException calling ITelecomService#isVoiceMailNumber.", e);
         }
         return false;
     }
@@ -746,12 +746,32 @@ public class TelecomManager {
                 return getTelecomService().hasVoiceMailNumber(accountHandle);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException calling isInCall().", e);
+            Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
         }
         return false;
     }
 
     /**
+     * Return the line 1 phone number for given phone account.
+     *
+     * @param accountHandle The handle for the account retrieve a number for.
+     * @return A string representation of the line 1 phone number.
+     *
+     * @hide
+     */
+    @SystemApi
+    public String getLine1Number(PhoneAccountHandle accountHandle) {
+        try {
+            if (isServiceConnected()) {
+                return getTelecomService().getLine1Number(accountHandle);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling ITelecomService#getLine1Number.", e);
+        }
+        return null;
+    }
+
+    /**
      * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
      * states).
      * <p>
index f8d7539..d2030f2 100644 (file)
@@ -126,6 +126,11 @@ interface ITelecomService {
     boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle);
 
     /**
+     * @see TelecomServiceImpl#getLine1Number
+     */
+    String getLine1Number(in PhoneAccountHandle accountHandle);
+
+    /**
      * @see TelecomServiceImpl#getDefaultPhoneApp
      */
     ComponentName getDefaultPhoneApp();