diff options
31 files changed, 862 insertions, 527 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 39685ae..56edc72 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 38cd126..d33c82b 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -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); + } } /** diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 12d4513..067073a 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -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); + } } /** diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 602a68c..8ebcacd 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -19,6 +19,8 @@ package android.util; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.SntpClient; import android.os.SystemClock; import android.provider.Settings; @@ -34,10 +36,13 @@ public class NtpTrustedTime implements TrustedTime { private static final boolean LOGD = false; private static NtpTrustedTime sSingleton; + private static Context sContext; private final String mServer; private final long mTimeout; + private ConnectivityManager mCM; + private boolean mHasCache; private long mCachedNtpTime; private long mCachedNtpElapsedRealtime; @@ -66,6 +71,7 @@ public class NtpTrustedTime implements TrustedTime { final String server = secureServer != null ? secureServer : defaultServer; sSingleton = new NtpTrustedTime(server, timeout); + sContext = context; } return sSingleton; @@ -78,6 +84,20 @@ public class NtpTrustedTime implements TrustedTime { return false; } + // We can't do this at initialization time: ConnectivityService might not be running yet. + synchronized (this) { + if (mCM == null) { + mCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + } + } + + final NetworkInfo ni = mCM == null ? null : mCM.getActiveNetworkInfo(); + if (ni == null || !ni.isConnected()) { + if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); + return false; + } + + if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); final SntpClient client = new SntpClient(); if (client.requestTime(mServer, (int) mTimeout)) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index cc8a440..ed75de3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16633,6 +16633,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (changed) { requestLayout(); + invalidateOutline(); } } diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index fe8b08b..d85bbb9 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -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); diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 7b64cf5..11fda2c 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -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); diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml index 3a66507..8917431 100644 --- a/core/res/res/drawable/ic_corp_badge.xml +++ b/core/res/res/drawable/ic_corp_badge.xml @@ -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> diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge.xml index 538dade..0273545 100644 --- a/core/res/res/drawable/ic_corp_icon_badge.xml +++ b/core/res/res/drawable/ic_corp_icon_badge.xml @@ -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-mcc214-mnc03/config.xml b/core/res/res/values-mcc214-mnc03/config.xml deleted file mode 100644 index aa16468..0000000 --- a/core/res/res/values-mcc214-mnc03/config.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 2009, 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 different hardware and product builds. Do not translate. --> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - - <!-- String containing the apn value for tethering. May be overriden by secure settings - TETHER_DUN_APN. Value is a comma separated series of strings: - "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type", - Or string format of ApnSettingV3. - note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> - <string-array translatable="false" name="config_tether_apndata"> - <item>Orange Internet PC,internet,,,orange,orange,,,,,214,03,1,DUN</item> - </string-array> - -</resources> diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml index 4637519..776b570 100644 --- a/core/res/res/values-mcc234-mnc33/config.xml +++ b/core/res/res/values-mcc234-mnc33/config.xml @@ -29,13 +29,4 @@ <item>23434</item> <item>23486</item> </string-array> - - <!-- String containing the apn value for tethering. May be overriden by secure settings - TETHER_DUN_APN. Value is a comma separated series of strings: - "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type", - Or string format of ApnSettingV3. - note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> - <string-array translatable="false" name="config_tether_apndata"> - <item>Consumer Broadband,consumerbroadband,,,,,,,,,234,33,,DUN</item> - </string-array> </resources> diff --git a/core/res/res/values-mcc222-mnc01/config.xml b/core/res/res/values-television/config.xml index 4b1981f..3435474 100644 --- a/core/res/res/values-mcc222-mnc01/config.xml +++ b/core/res/res/values-television/config.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- /* -** Copyright 2009, The Android Open Source Project +** 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. @@ -18,15 +18,9 @@ --> <!-- These resources are around just to allow their values to be customized - for different hardware and product builds. Do not translate. --> + for TV products. Do not translate. --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- String containing the apn value for tethering. May be overriden by secure settings - TETHER_DUN_APN. Value is a comma separated series of strings: - "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type", - Or string format of ApnSettingV3. - note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> - <string-array translatable="false" name="config_tether_apndata"> - <item>TIM WEB,ibox.tim.it,,,,,,,,,222,01,,DUN</item> - </string-array> + <!-- Flags enabling default window features. See Window.java --> + <bool name="config_defaultWindowFeatureOptionsPanel">false</bool> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 24ec7ce..0c28c86 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1460,9 +1460,9 @@ <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> diff --git a/docs/html/training/location/display-address.jd b/docs/html/training/location/display-address.jd index 621b082..516f14f 100644 --- a/docs/html/training/location/display-address.jd +++ b/docs/html/training/location/display-address.jd @@ -1,280 +1,468 @@ 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> -<ProgressBar -android:id="@+id/address_progress" -android:layout_width="wrap_content" -android:layout_height="wrap_content" -android:layout_centerHorizontal="true" -android:indeterminate="true" -android:visibility="gone" /> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.gms.location.sample.locationupdates" > + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> +</manifest> </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 { +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.gms.location.sample.locationaddress" > + <application + ... + <service + android:name=".FetchAddressIntentService" + android:exported="false"/> + </application> ... - private TextView mAddress; - private ProgressBar mActivityIndicator; +</manifest> +</pre> + +<p class="note"><strong>Note:</strong> The {@code <service>} 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> +@Override +protected void onHandleIntent(Intent intent) { + Geocoder geocoder = new Geocoder(this, Locale.getDefault()); ... - @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> +@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<Address> 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<Location, Void, String> { - 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 - * - * @params params One or more Location objects - * @return A string containing the address of the current - * location, or an empty string if no address can be found, - * or an error message - */ - @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<Address> 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 && addresses.size() > 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( - "%s, %s, %s", - // If there's a street address, add it - address.getMaxAddressLineIndex() > 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<String> addressFragments = new ArrayList<String>(); + + // 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<Location, Void, String> { - ... - /** - * 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. - */ - @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. - * - * @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 >= - Build.VERSION_CODES.GINGERBREAD - && - 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 { + ... + @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); + } + + @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> diff --git a/docs/html/training/wearables/data-layer/data-items.jd b/docs/html/training/wearables/data-layer/data-items.jd index 12babbf..49a8d32 100644 --- a/docs/html/training/wearables/data-layer/data-items.jd +++ b/docs/html/training/wearables/data-layer/data-items.jd @@ -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<DataApi.DataItemResult> 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<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> -@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; + + @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(); + } + + @Override + protected void onResume() { + super.onStart(); + mGoogleApiClient.connect(); + } + + @Override + public void onConnected(Bundle bundle) { + <strong>Wearable.DataApi.addListener</strong>(mGoogleApiClient, this); + } + + @Override + protected void onPause() { + super.onPause(); + <strong>Wearable.DataApi.removeListener</strong>(mGoogleApiClient, this); + mGoogleApiClient.disconnect(); + } + + @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> diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd index 6a3949a..c797f68 100644 --- a/docs/html/training/wearables/data-layer/events.jd +++ b/docs/html/training/wearables/data-layer/events.jd @@ -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; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -314,4 +316,5 @@ public class MainActivity extends Activity implements } } } +} </pre> diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 13cdc69..5d9355a 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -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; diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index 781988d..c80adfa 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -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)); diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index b8e850a..8b2e203 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -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/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 1f98670..281fde3 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -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) { diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index fddb54e..d6abce9 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -55,7 +55,7 @@ public class NetworkTimeUpdateService { private static final int EVENT_AUTO_TIME_CHANGED = 1; private static final int EVENT_POLL_NETWORK_TIME = 2; - private static final int EVENT_NETWORK_CONNECTED = 3; + private static final int EVENT_NETWORK_CHANGED = 3; private static final String ACTION_POLL = "com.android.server.NetworkTimeUpdateService.action.POLL"; @@ -248,18 +248,8 @@ public class NetworkTimeUpdateService { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - // There is connectivity - final ConnectivityManager connManager = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - final NetworkInfo netInfo = connManager.getActiveNetworkInfo(); - if (netInfo != null) { - // Verify that it's a WIFI connection - if (netInfo.getState() == NetworkInfo.State.CONNECTED && - (netInfo.getType() == ConnectivityManager.TYPE_WIFI || - netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) { - mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget(); - } - } + // Don't bother checking if we have connectivity, NtpTrustedTime does that for us. + mHandler.obtainMessage(EVENT_NETWORK_CHANGED).sendToTarget(); } } }; @@ -276,7 +266,7 @@ public class NetworkTimeUpdateService { switch (msg.what) { case EVENT_AUTO_TIME_CHANGED: case EVENT_POLL_NETWORK_TIME: - case EVENT_NETWORK_CONNECTED: + case EVENT_NETWORK_CHANGED: onPollNetworkTime(msg.what); break; } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 6d28382..aefbf60 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -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; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 40bcf8e..e8f3757 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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(); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 0b49c9c..b1b2a5c 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -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)); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4e932c1..6497cd7 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -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); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 5c8e191..32787d8 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -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(); diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 41499be..c376744 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -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) diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 2af56fe..50b2262 100644 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -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; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2ca5629..fd4c016 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -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); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 6621726..1a6b292 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -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> diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index f8d7539..d2030f2 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -126,6 +126,11 @@ interface ITelecomService { boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle); /** + * @see TelecomServiceImpl#getLine1Number + */ + String getLine1Number(in PhoneAccountHandle accountHandle); + + /** * @see TelecomServiceImpl#getDefaultPhoneApp */ ComponentName getDefaultPhoneApp(); |
