OSDN Git Service

Merge "Import translations. DO NOT MERGE" into nyc-dev
authorBill Yi <byi@google.com>
Wed, 6 Apr 2016 17:10:26 +0000 (17:10 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 6 Apr 2016 17:10:27 +0000 (17:10 +0000)
67 files changed:
api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/app/NotificationManager.java
core/java/android/app/admin/DevicePolicyManager.java
core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
core/java/android/inputmethodservice/InputMethodService.java
core/java/android/net/ConnectivityManager.java
core/java/android/net/DnsPinger.java [deleted file]
core/java/android/os/INetworkManagementService.aidl
core/java/android/text/BoringLayout.java
core/java/android/text/StaticLayout.java
core/java/android/view/accessibility/AccessibilityNodeInfo.java
core/java/android/widget/TextView.java
core/java/com/android/internal/util/FastXmlSerializer.java
core/java/com/android/internal/widget/FloatingToolbar.java
core/res/AndroidManifest.xml
core/res/res/values-be-rBY/strings.xml
core/res/res/values-eu-rES/strings.xml
core/res/res/values-zh-rCN/strings.xml
core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
media/java/android/media/midi/IMidiDeviceServer.aidl
media/java/android/media/midi/MidiDevice.java
media/java/android/media/midi/MidiDeviceServer.java
media/jni/android_mtp_MtpDatabase.cpp
packages/DocumentsUI/res/drawable/drag_shadow_background.xml [new file with mode: 0644]
packages/DocumentsUI/res/layout/drag_shadow_layout.xml [new file with mode: 0644]
packages/DocumentsUI/res/values/dimens.xml
packages/DocumentsUI/res/values/strings.xml
packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
packages/PrintSpooler/res/layout/print_activity_controls.xml
packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
packages/SystemUI/AndroidManifest.xml
packages/SystemUI/res/drawable/tv_pip_close_button.xml
packages/SystemUI/res/drawable/tv_pip_full_button.xml
packages/SystemUI/res/drawable/tv_pip_pause_button.xml
packages/SystemUI/res/drawable/tv_pip_play_button.xml
packages/SystemUI/res/values-bs-rBA/strings.xml
packages/SystemUI/res/values-fa/strings.xml
packages/SystemUI/res/values-gl-rES/strings.xml
packages/SystemUI/res/values-nb/strings.xml
packages/SystemUI/res/values-ro/strings.xml
packages/SystemUI/res/values-ru/strings.xml
packages/SystemUI/res/values-zh-rCN/strings.xml
packages/SystemUI/res/values/dimens_tv.xml
packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java [deleted file]
packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
services/core/java/com/android/server/AppOpsService.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/NetworkManagementService.java
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java

index 2df13bb..40a92b9 100644 (file)
@@ -5921,7 +5921,7 @@ package android.app.admin {
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -23452,6 +23452,7 @@ package android.net {
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -44101,8 +44102,6 @@ package android.view.accessibility {
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
index b7ac148..9ed529f 100644 (file)
@@ -6070,7 +6070,7 @@ package android.app.admin {
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -25188,6 +25188,7 @@ package android.net {
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
     method public boolean isTetheringSupported();
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -46844,8 +46845,6 @@ package android.view.accessibility {
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
index 200d719..dea7fc1 100644 (file)
@@ -5925,7 +5925,7 @@ package android.app.admin {
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
-    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
+    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -23517,6 +23517,7 @@ package android.net {
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
+    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
     method public void releaseNetworkRequest(android.app.PendingIntent);
@@ -44175,8 +44176,6 @@ package android.view.accessibility {
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT = "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
     field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
index 0d4729d..47bff64 100644 (file)
@@ -153,25 +153,31 @@ public class NotificationManager
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Normal interruption filter.
+     *     Normal interruption filter - no notifications are suppressed.
      */
     public static final int INTERRUPTION_FILTER_ALL = 1;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Priority interruption filter.
+     *     Priority interruption filter - all notifications are suppressed except those that match
+     *     the priority criteria. Some audio streams are muted. See
+     *     {@link Policy#priorityCallSenders}, {@link Policy#priorityCategories},
+     *     {@link Policy#priorityMessageSenders} to define or query this criteria. Users can
+     *     additionally specify packages that can bypass this interruption filter.
      */
     public static final int INTERRUPTION_FILTER_PRIORITY = 2;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     No interruptions filter.
+     *     No interruptions filter - all notifications are suppressed and all audio streams (except
+     *     those used for phone calls) and vibrations are muted.
      */
     public static final int INTERRUPTION_FILTER_NONE = 3;
 
     /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
-     *     Alarms only interruption filter.
+     *     Alarms only interruption filter - all notifications except those of category
+     *     {@link Notification#CATEGORY_ALARM} are suppressed. Some audio streams are muted.
      */
     public static final int INTERRUPTION_FILTER_ALARMS = 4;
 
index b924327..856a0f1 100644 (file)
@@ -2977,17 +2977,21 @@ public class DevicePolicyManager {
      * @return {@code true} if the package is set as always-on VPN controller; {@code false}
      *         otherwise.
      * @throws SecurityException if {@code admin} is not a device or a profile owner.
+     * @throws NameNotFoundException if {@code vpnPackage} is not installed.
+     * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
+     *         set as always-on, or if always-on VPN is not available.
      */
-    public boolean setAlwaysOnVpnPackage(@NonNull ComponentName admin,
-            @Nullable String vpnPackage) {
+    public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage)
+            throws NameNotFoundException, UnsupportedOperationException {
         if (mService != null) {
             try {
-                return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
+                if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage)) {
+                    throw new NameNotFoundException(vpnPackage);
+                }
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
-        return false;
     }
 
     /**
@@ -5849,8 +5853,43 @@ public class DevicePolicyManager {
     /**
      * Called by the profile owner of a managed profile to obtain a {@link DevicePolicyManager}
      * whose calls act on the parent profile.
-     * <p>
-     * Note only some methods will work on the parent Manager.
+     *
+     * <p>The following methods are supported for the parent instance, all other methods will
+     * throw a SecurityException when called on the parent instance:
+     * <ul>
+     * <li>{@link #getPasswordQuality}</li>
+     * <li>{@link #setPasswordQuality}</li>
+     * <li>{@link #getPasswordMinimumLength}</li>
+     * <li>{@link #setPasswordMinimumLength}</li>
+     * <li>{@link #getPasswordMinimumUpperCase}</li>
+     * <li>{@link #setPasswordMinimumUpperCase}</li>
+     * <li>{@link #getPasswordMinimumLowerCase}</li>
+     * <li>{@link #setPasswordMinimumLowerCase}</li>
+     * <li>{@link #getPasswordMinimumLetters}</li>
+     * <li>{@link #setPasswordMinimumLetters}</li>
+     * <li>{@link #getPasswordMinimumNumeric}</li>
+     * <li>{@link #setPasswordMinimumNumeric}</li>
+     * <li>{@link #getPasswordMinimumSymbols}</li>
+     * <li>{@link #setPasswordMinimumSymbols}</li>
+     * <li>{@link #getPasswordMinimumNonLetter}</li>
+     * <li>{@link #setPasswordMinimumNonLetter}</li>
+     * <li>{@link #getPasswordHistoryLength}</li>
+     * <li>{@link #setPasswordHistoryLength}</li>
+     * <li>{@link #getPasswordExpirationTimeout}</li>
+     * <li>{@link #setPasswordExpirationTimeout}</li>
+     * <li>{@link #getPasswordExpiration}</li>
+     * <li>{@link #isActivePasswordSufficient}</li>
+     * <li>{@link #getCurrentFailedPasswordAttempts}</li>
+     * <li>{@link #getMaximumFailedPasswordsForWipe}</li>
+     * <li>{@link #setMaximumFailedPasswordsForWipe}</li>
+     * <li>{@link #getMaximumTimeToLock}</li>
+     * <li>{@link #setMaximumTimeToLock}</li>
+     * <li>{@link #lockNow}</li>
+     * <li>{@link #getKeyguardDisabledFeatures}</li>
+     * <li>{@link #setKeyguardDisabledFeatures}</li>
+     * <li>{@link #getTrustAgentConfiguration}</li>
+     * <li>{@link #setTrustAgentConfiguration}</li>
+     * </ul>
      *
      * @return a new instance of {@link DevicePolicyManager} that acts on the parent profile.
      * @throws SecurityException if {@code admin} is not a profile owner.
index b2f6c1d..ef5f6d7 100644 (file)
@@ -55,7 +55,9 @@ public class ICameraDeviceUserWrapper {
     }
 
     public void unlinkToDeath(IBinder.DeathRecipient recipient, int flags) {
-        mRemoteDevice.asBinder().unlinkToDeath(recipient, flags);
+        if (mRemoteDevice.asBinder() != null) {
+            mRemoteDevice.asBinder().unlinkToDeath(recipient, flags);
+        }
     }
 
     public void disconnect()  {
index 9d53a00..cc201bc 100644 (file)
@@ -717,7 +717,11 @@ public class InputMethodService extends AbstractInputMethodService {
                 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
                         ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
-                mService.updateInputViewShown();
+                // In Android M and prior, state change of
+                // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
+                // #onConfigurationChanged().  For compatibility reasons, we reset the internal
+                // state as if configuration was changed.
+                mService.resetStateForNewConfiguration();
             }
         }
 
@@ -884,7 +888,10 @@ public class InputMethodService extends AbstractInputMethodService {
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        resetStateForNewConfiguration();
+    }
 
+    private void resetStateForNewConfiguration() {
         boolean visible = mWindowVisible;
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
index f0673ff..b452341 100644 (file)
@@ -3021,7 +3021,6 @@ public class ConnectivityManager {
      *
      * @param networkCallback The {@link NetworkCallback} that the system will call as the
      *                        system default network changes.
-     * @hide
      */
     public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
         // This works because if the NetworkCapabilities are null,
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
deleted file mode 100644 (file)
index 7acf3f5..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package android.net;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.util.Protocol;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketTimeoutException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Performs a simple DNS "ping" by sending a "server status" query packet to the
- * DNS server. As long as the server replies, we consider it a success.
- * <p>
- * We do not use a simple hostname lookup because that could be cached and the
- * API may not differentiate between a time out and a failure lookup (which we
- * really care about).
- * <p>
- *
- * @hide
- */
-public final class DnsPinger extends Handler {
-    private static final boolean DBG = false;
-
-    private static final int RECEIVE_POLL_INTERVAL_MS = 200;
-    private static final int DNS_PORT = 53;
-
-    /** Short socket timeout so we don't block one any 'receive' call */
-    private static final int SOCKET_TIMEOUT_MS = 1;
-
-    /** Used to generate IDs */
-    private static final Random sRandom = new Random();
-    private static final AtomicInteger sCounter = new AtomicInteger();
-
-    private ConnectivityManager mConnectivityManager = null;
-    private final Context mContext;
-    private final int mConnectionType;
-    private final Handler mTarget;
-    private final ArrayList<InetAddress> mDefaultDns;
-    private String TAG;
-
-    //Invalidates old dns requests upon a cancel
-    private AtomicInteger mCurrentToken = new AtomicInteger();
-
-    private static final int BASE = Protocol.BASE_DNS_PINGER;
-
-    /**
-     * Async response packet for dns pings.
-     * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
-     * arg2 is the delay, or is negative on error.
-     */
-    public static final int DNS_PING_RESULT = BASE;
-    /** An error code for a {@link #DNS_PING_RESULT} packet */
-    public static final int TIMEOUT = -1;
-    /** An error code for a {@link #DNS_PING_RESULT} packet */
-    public static final int SOCKET_EXCEPTION = -2;
-
-    /**
-     * Send a new ping via a socket.  arg1 is ID, arg2 is timeout, obj is InetAddress to ping
-     */
-    private static final int ACTION_PING_DNS = BASE + 1;
-    private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
-    private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
-
-    private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
-    private int mEventCounter;
-
-    private class ActivePing {
-        DatagramSocket socket;
-        int internalId;
-        short packetId;
-        int timeout;
-        Integer result;
-        long start = SystemClock.elapsedRealtime();
-    }
-
-    /* Message argument for ACTION_PING_DNS */
-    private class DnsArg {
-        InetAddress dns;
-        int seq;
-
-        DnsArg(InetAddress d, int s) {
-            dns = d;
-            seq = s;
-        }
-    }
-
-    public DnsPinger(Context context, String TAG, Looper looper,
-            Handler target, int connectionType) {
-        super(looper);
-        this.TAG = TAG;
-        mContext = context;
-        mTarget = target;
-        mConnectionType = connectionType;
-        if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
-            throw new IllegalArgumentException("Invalid connectionType in constructor: "
-                    + connectionType);
-        }
-        mDefaultDns = new ArrayList<InetAddress>();
-        mDefaultDns.add(getDefaultDns());
-        mEventCounter = 0;
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-            case ACTION_PING_DNS:
-                DnsArg dnsArg = (DnsArg) msg.obj;
-                if (dnsArg.seq != mCurrentToken.get()) {
-                    break;
-                }
-                try {
-                    ActivePing newActivePing = new ActivePing();
-                    InetAddress dnsAddress = dnsArg.dns;
-                    newActivePing.internalId = msg.arg1;
-                    newActivePing.timeout = msg.arg2;
-                    newActivePing.socket = new DatagramSocket();
-                    // Set some socket properties
-                    newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
-
-                    // Try to bind but continue ping if bind fails
-                    try {
-                        newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
-                                getCurrentLinkProperties().getInterfaceName()));
-                    } catch (Exception e) {
-                        loge("sendDnsPing::Error binding to socket " + e);
-                    }
-
-                    newActivePing.packetId = (short) sRandom.nextInt();
-                    byte[] buf = mDnsQuery.clone();
-                    buf[0] = (byte) (newActivePing.packetId >> 8);
-                    buf[1] = (byte) newActivePing.packetId;
-
-                    // Send the DNS query
-                    DatagramPacket packet = new DatagramPacket(buf,
-                            buf.length, dnsAddress, DNS_PORT);
-                    if (DBG) {
-                        log("Sending a ping " + newActivePing.internalId +
-                                " to " + dnsAddress.getHostAddress()
-                                + " with packetId " + newActivePing.packetId + ".");
-                    }
-
-                    newActivePing.socket.send(packet);
-                    mActivePings.add(newActivePing);
-                    mEventCounter++;
-                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
-                            RECEIVE_POLL_INTERVAL_MS);
-                } catch (IOException e) {
-                    sendResponse(msg.arg1, -9999, SOCKET_EXCEPTION);
-                }
-                break;
-            case ACTION_LISTEN_FOR_RESPONSE:
-                if (msg.arg1 != mEventCounter) {
-                    break;
-                }
-                for (ActivePing curPing : mActivePings) {
-                    try {
-                        /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
-                        byte[] responseBuf = new byte[2];
-                        DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
-                        curPing.socket.receive(replyPacket);
-                        // Check that ID field matches (we're throwing out the rest of the packet)
-                        if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
-                                responseBuf[1] == (byte) curPing.packetId) {
-                            curPing.result =
-                                    (int) (SystemClock.elapsedRealtime() - curPing.start);
-                        } else {
-                            if (DBG) {
-                                log("response ID didn't match, ignoring packet");
-                            }
-                        }
-                    } catch (SocketTimeoutException e) {
-                        // A timeout here doesn't mean anything - squelsh this exception
-                    } catch (Exception e) {
-                        if (DBG) {
-                            log("DnsPinger.pingDns got socket exception: " + e);
-                        }
-                        curPing.result = SOCKET_EXCEPTION;
-                    }
-                }
-                Iterator<ActivePing> iter = mActivePings.iterator();
-                while (iter.hasNext()) {
-                   ActivePing curPing = iter.next();
-                   if (curPing.result != null) {
-                       sendResponse(curPing.internalId, curPing.packetId, curPing.result);
-                       curPing.socket.close();
-                       iter.remove();
-                   } else if (SystemClock.elapsedRealtime() >
-                                  curPing.start + curPing.timeout) {
-                       sendResponse(curPing.internalId, curPing.packetId, TIMEOUT);
-                       curPing.socket.close();
-                       iter.remove();
-                   }
-                }
-                if (!mActivePings.isEmpty()) {
-                    sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
-                            RECEIVE_POLL_INTERVAL_MS);
-                }
-                break;
-            case ACTION_CANCEL_ALL_PINGS:
-                for (ActivePing activePing : mActivePings)
-                    activePing.socket.close();
-                mActivePings.clear();
-                break;
-        }
-    }
-
-    /**
-     * Returns a list of DNS addresses, coming from either the link properties of the
-     * specified connection or the default system DNS if the link properties has no dnses.
-     * @return a non-empty non-null list
-     */
-    public List<InetAddress> getDnsList() {
-        LinkProperties curLinkProps = getCurrentLinkProperties();
-        if (curLinkProps == null) {
-            loge("getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
-            return mDefaultDns;
-        }
-
-        Collection<InetAddress> dnses = curLinkProps.getDnsServers();
-        if (dnses == null || dnses.size() == 0) {
-            loge("getDns::LinkProps has null dns - returning default");
-            return mDefaultDns;
-        }
-
-        return new ArrayList<InetAddress>(dnses);
-    }
-
-    /**
-     * Send a ping.  The response will come via a {@link #DNS_PING_RESULT} to the handler
-     * specified at creation.
-     * @param dns address of dns server to ping
-     * @param timeout timeout for ping
-     * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
-     */
-    public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
-        int id = sCounter.incrementAndGet();
-        sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout,
-                new DnsArg(dns, mCurrentToken.get())), delay);
-        return id;
-    }
-
-    public void cancelPings() {
-        mCurrentToken.incrementAndGet();
-        obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
-    }
-
-    private void sendResponse(int internalId, int externalId, int responseVal) {
-        if(DBG) {
-            log("Responding to packet " + internalId +
-                    " externalId " + externalId +
-                    " and val " + responseVal);
-        }
-        mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
-    }
-
-    private LinkProperties getCurrentLinkProperties() {
-        if (mConnectivityManager == null) {
-            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-        }
-
-        return mConnectivityManager.getLinkProperties(mConnectionType);
-    }
-
-    private InetAddress getDefaultDns() {
-        String dns = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.DEFAULT_DNS_SERVER);
-        if (dns == null || dns.length() == 0) {
-            dns = mContext.getResources().getString(
-                    com.android.internal.R.string.config_default_dns_server);
-        }
-        try {
-            return NetworkUtils.numericToInetAddress(dns);
-        } catch (IllegalArgumentException e) {
-            loge("getDefaultDns::malformed default dns address");
-            return null;
-        }
-    }
-
-    private static final byte[] mDnsQuery = new byte[] {
-        0, 0, // [0-1] is for ID (will set each time)
-        1, 0, // [2-3] are flags.  Set byte[2] = 1 for recursion desired (RD) on.  Currently on.
-        0, 1, // [4-5] bytes are for number of queries (QCOUNT)
-        0, 0, // [6-7] unused count field for dns response packets
-        0, 0, // [8-9] unused count field for dns response packets
-        0, 0, // [10-11] unused count field for dns response packets
-        3, 'w', 'w', 'w',
-        6, 'g', 'o', 'o', 'g', 'l', 'e',
-        3, 'c', 'o', 'm',
-        0,    // null terminator of address (also called empty TLD)
-        0, 1, // QTYPE, set to 1 = A (host address)
-        0, 1  // QCLASS, set to 1 = IN (internet)
-    };
-
-    private void log(String s) {
-        Log.d(TAG, s);
-    }
-
-    private void loge(String s) {
-        Log.e(TAG, s);
-    }
-}
index 24a6cdf..68b0a9f 100644 (file)
@@ -328,11 +328,6 @@ interface INetworkManagementService
      */
     void setDnsServersForNetwork(int netId, in String[] servers, String domains);
 
-    /**
-     * Flush the DNS cache associated with the specified network.
-     */
-    void flushNetworkDnsCache(int netId);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
index 328fe99..7f0021d 100644 (file)
@@ -183,8 +183,10 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
 
         if (includepad) {
             spacing = metrics.bottom - metrics.top;
+            mDesc = metrics.bottom;
         } else {
             spacing = metrics.descent - metrics.ascent;
+            mDesc = metrics.descent;
         }
 
         mBottom = spacing;
@@ -208,8 +210,6 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             mTopPadding = metrics.top - metrics.ascent;
             mBottomPadding = metrics.bottom - metrics.descent;
         }
-
-        mDesc = spacing + mBottomPadding + (includepad ? metrics.top : metrics.ascent);
     }
 
     /**
index 6a33579..94ce57a 100644 (file)
@@ -1132,22 +1132,12 @@ public class StaticLayout extends Layout {
 
     @Override
     public int getLineTop(int line) {
-        int top = mLines[mColumns * line + TOP];
-        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount &&
-                line != mLineCount) {
-            top += getBottomPadding();
-        }
-        return top;
+        return mLines[mColumns * line + TOP];
     }
 
     @Override
     public int getLineDescent(int line) {
-        int descent = mLines[mColumns * line + DESCENT];
-        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
-                line != mLineCount) {
-            descent += getBottomPadding();
-        }
-        return descent;
+        return mLines[mColumns * line + DESCENT];
     }
 
     @Override
index 1482111..02d2a8b 100644 (file)
@@ -328,36 +328,6 @@ public class AccessibilityNodeInfo implements Parcelable {
     // Action arguments
 
     /**
-     * Argument for specifying index of {@link android.text.style.ClickableSpan} the click action is
-     * related to.
-     * <p>
-     * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong>
-     * {@link AccessibilityAction#ACTION_CLICK}
-     * </p>
-     *
-     * @see AccessibilityAction#ACTION_CLICK
-     */
-    public static final String ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT =
-            "android.view.accessibility.action.ARGUMENT_CLICK_SPAN_INDEX_INT";
-
-    /**
-     * Argument for specifying index of character in the text which contains
-     * {@link android.text.style.ClickableSpan} the click action is
-     * related to. If there is more than one {@link android.text.style.ClickableSpan} assigned for
-     * the range the character is in only the first span would be clicked.
-     * <p>
-     * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong>
-     * {@link AccessibilityAction#ACTION_CLICK}
-     * </p>
-     *
-     * @see AccessibilityAction#ACTION_CLICK
-     */
-    public static final String ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT =
-            "android.view.accessibility.action.ARGUMENT_CLICK_CHARACTER_INDEX_INT";
-
-    /**
      * Argument for which movement granularity to be used when traversing the node text.
      * <p>
      * <strong>Type:</strong> int<br>
@@ -3391,33 +3361,6 @@ public class AccessibilityNodeInfo implements Parcelable {
 
         /**
          * Action that clicks on the node info.
-         *
-         * <p>
-         * If a specific {@link android.text.style.ClickableSpan} within node's text content is
-         * supposed to be clicked, then one of {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT} or
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} arguments should be specified.
-         * If both arguments are set {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} would
-         * be ignored.<br>
-         *
-         * {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT} specifies index of corresponding
-         * {@link android.text.style.ClickableSpan} in {@link android.text.SpannableString}.<br>
-         *
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT} specifies index of character
-         * that could contain one or more spans.
-         * </p>
-         *
-         * <p>
-         * <strong>Optional arguments:</strong>
-         * {@link #ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT},
-         * {@link #ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT}<br>
-         * <strong>Example:</strong> Perform click on 3rd {@link android.text.style.ClickableSpan}
-         * inside {@link android.text.SpannableString} in node's text.
-         * <code><pre><p>
-         *   Bundle arguments = new Bundle();
-         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT, 3);
-         *   info.performAction(AccessibilityAction.ACTION_CLICK.getId(), arguments);
-         * </code></pre></p>
-         * </p>
          */
         public static final AccessibilityAction ACTION_CLICK =
                 new AccessibilityAction(
index 3b7b16d..4483b7b 100644 (file)
@@ -9210,52 +9210,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
     private boolean performAccessibilityActionClick(Bundle arguments) {
         boolean handled = false;
-        boolean processed = false;
 
         if (!isEnabled()) {
             return false;
         }
 
-        if (arguments != null && arguments.containsKey(
-                AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT)) {
-            int spanIndex = arguments.getInt(
-                    AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_SPAN_INDEX_INT, -1);
-            if (spanIndex >= 0 && hasSpannableText()) {
-                ClickableSpan[] spans = ((Spannable) mText).getSpans(0,
-                        mText.length(), ClickableSpan.class);
-                if (spans != null && spans.length > spanIndex && spans[spanIndex] != null) {
-                    // Simulate View.onTouchEvent for an ACTION_UP event
-                    if (isFocusable() && !isFocused()) {
-                        requestFocus();
-                    }
-                    spans[spanIndex].onClick(this);
-                    handled = true;
-                }
-            }
-            processed = true;
-        }
-
-        if (!processed && arguments != null &&  arguments.containsKey(
-                AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT)) {
-            int characterIndex = arguments.getInt(
-                    AccessibilityNodeInfo.ACTION_ARGUMENT_CLICK_CHARACTER_INDEX_INT, -1);
-            if (characterIndex >= 0 && hasSpannableText()) {
-                ClickableSpan[] spans = ((Spannable) mText).getSpans(characterIndex,
-                        characterIndex, ClickableSpan.class);
-                // click only on the first span to keep parity with onTouch() implementation
-                if (spans != null && spans.length > 0 && spans[0] != null) {
-                    // Simulate View.onTouchEvent for an ACTION_UP event
-                    if (isFocusable() && !isFocused()) {
-                        requestFocus();
-                    }
-                    spans[0].onClick(this);
-                    handled = true;
-                }
-            }
-            processed = true;
-        }
-
-        if (!processed && (isClickable() || isLongClickable())) {
+        if (isClickable() || isLongClickable()) {
             // Simulate View.onTouchEvent for an ACTION_UP event
             if (isFocusable() && !isFocused()) {
                 requestFocus();
index 7a04080..3c1d2d6 100644 (file)
@@ -28,6 +28,7 @@ import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
 
@@ -38,14 +39,14 @@ import java.nio.charset.UnsupportedCharsetException;
  */
 public class FastXmlSerializer implements XmlSerializer {
     private static final String ESCAPE_TABLE[] = new String[] {
-        null,     null,     null,     null,     null,     null,     null,     null,  // 0-7
-        null,     null,     null,     null,     null,     null,     null,     null,  // 8-15
-        null,     null,     null,     null,     null,     null,     null,     null,  // 16-23
-        null,     null,     null,     null,     null,     null,     null,     null,  // 24-31
-        null,     null,     "&quot;", null,     null,     null,     "&amp;",  null,  // 32-39
-        null,     null,     null,     null,     null,     null,     null,     null,  // 40-47
-        null,     null,     null,     null,     null,     null,     null,     null,  // 48-55
-        null,     null,     null,     null,     "&lt;",   null,     "&gt;",   null,  // 56-63
+        "&#0;",   "&#1;",   "&#2;",   "&#3;",  "&#4;",    "&#5;",   "&#6;",  "&#7;",  // 0-7
+        "&#8;",   "&#9;",   "&#10;",  "&#11;", "&#12;",   "&#13;",  "&#14;", "&#15;", // 8-15
+        "&#16;",  "&#17;",  "&#18;",  "&#19;", "&#20;",   "&#21;",  "&#22;", "&#23;", // 16-23
+        "&#24;",  "&#25;",  "&#26;",  "&#27;", "&#28;",   "&#29;",  "&#30;", "&#31;", // 24-31
+        null,     null,     "&quot;", null,     null,     null,     "&amp;",  null,   // 32-39
+        null,     null,     null,     null,     null,     null,     null,     null,   // 40-47
+        null,     null,     null,     null,     null,     null,     null,     null,   // 48-55
+        null,     null,     null,     null,     "&lt;",   null,     "&gt;",   null,   // 56-63
     };
 
     private static final int BUFFER_LEN = 8192;
@@ -310,7 +311,9 @@ public class FastXmlSerializer implements XmlSerializer {
             throw new IllegalArgumentException();
         if (true) {
             try {
-                mCharset = Charset.forName(encoding).newEncoder();
+                mCharset = Charset.forName(encoding).newEncoder()
+                        .onMalformedInput(CodingErrorAction.REPLACE)
+                        .onUnmappableCharacter(CodingErrorAction.REPLACE);
             } catch (IllegalCharsetNameException e) {
                 throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
                         encoding).initCause(e));
index da223a6..1848fe8 100644 (file)
@@ -1460,6 +1460,7 @@ public final class FloatingToolbar {
                 super(Preconditions.checkNotNull(popup).mContext);
                 this.mPopup = popup;
                 setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
+                setScrollIndicators(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
             }
 
             @Override
index 9219e81..88d75dd 100644 (file)
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
 
     <protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
-    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
     <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_POLL" />
     <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_UPDATED" />
     <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
     <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
     <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
 
-    <!-- @hide UCE service Notification -->
+    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
     <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
+
+    <protected-broadcast android:name="com.android.internal.location.ALARM_WAKEUP" />
+    <protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
+    <protected-broadcast android:name="android.intent.action.GLOBAL_BUTTON" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
index 73a8e04..8a23529 100644 (file)
     <string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Пераключыцца на асабісты"</string>
-    <string name="managed_profile_label" msgid="5289992269827577857">"Пераключыцца на рабочы"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"Пераключыцца на працоўны"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Кантакты"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"атрымліваць доступ да вашых кантактаў"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
index a8e0285..ea666d9 100644 (file)
     <string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
     <string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
     <string name="hardware" msgid="194658061510127999">"Erakutsi teklatu birtuala"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguratu teklatua fisikoa"</string>
+    <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguratu teklatu fisikoa"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
index c216be8..3b26e46 100644 (file)
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
-    <string name="user_owner_label" msgid="1119010402169916617">"切换“个人”"</string>
-    <string name="managed_profile_label" msgid="5289992269827577857">"切换“工作”"</string>
+    <string name="user_owner_label" msgid="1119010402169916617">"切换“个人”"</string>
+    <string name="managed_profile_label" msgid="5289992269827577857">"切换“工作”"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"已被管理员删除"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,省电模式会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n省电模式会在设备充电时自动关闭。"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d 分钟(到<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">1 分钟(到<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
index 5f36c2d..3cef336 100644 (file)
 
 package com.android.internal.util;
 
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.Xml;
+
 import junit.framework.TestCase;
 
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Tests for {@link FastXmlSerializer}
  */
+@SmallTest
 public class FastXmlSerializerTest extends TestCase {
+    private static final String TAG = "FastXmlSerializerTest";
+
+    private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH TRUE.
+
+    private static final String ROOT_TAG = "root";
+    private static final String ATTR = "attr";
+
     public void testEmptyText() throws Exception {
         final ByteArrayOutputStream stream = new ByteArrayOutputStream();
 
@@ -44,4 +60,93 @@ public class FastXmlSerializerTest extends TestCase {
         assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                 + "<string name=\"meow\"></string>\n", stream.toString());
     }
+
+    private boolean checkPreserved(String description, String str) {
+        boolean ok = true;
+        byte[] data;
+        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            final XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(baos, StandardCharsets.UTF_16.name());
+            out.startDocument(null, true);
+
+            out.startTag(null, ROOT_TAG);
+            out.attribute(null, ATTR, str);
+            out.text(str);
+            out.endTag(null, ROOT_TAG);
+
+            out.endDocument();
+            baos.flush();
+            data = baos.toByteArray();
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to serialize: " + description, e);
+            return false;
+        }
+
+        if (ENABLE_DUMP) {
+            Log.d(TAG, "Dump:");
+            Log.d(TAG, new String(data));
+        }
+
+        try (final ByteArrayInputStream baos = new ByteArrayInputStream(data)) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(baos, StandardCharsets.UTF_16.name());
+
+            int type;
+            String tag = null;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type == XmlPullParser.START_TAG) {
+                    tag = parser.getName();
+                    if (ROOT_TAG.equals(tag)) {
+                        String read = parser.getAttributeValue(null, ATTR);
+                        if (!str.equals(read)) {
+                            Log.e(TAG, "Attribute not preserved: " + description
+                                    + " input=\"" + str + "\", but read=\"" + read + "\"");
+                            ok = false;
+                        }
+                    }
+                }
+                if (type == XmlPullParser.TEXT && ROOT_TAG.equals(tag)) {
+                    String read = parser.getText();
+                    if (!str.equals(parser.getText())) {
+                        Log.e(TAG, "Text not preserved: " + description
+                                + " input=\"" + str + "\", but read=\"" + read + "\"");
+                        ok = false;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to parse: " + description, e);
+            return false;
+        }
+        return ok;
+    }
+
+    private boolean check(String description, String str) throws Exception {
+        boolean ok = false;
+        ok |= checkPreserved(description, str);
+        ok |= checkPreserved(description + " wrapped with spaces" ,"  " + str + "  ");
+        return ok;
+    }
+
+    @LargeTest
+    public void testAllCharacters() throws Exception {
+        boolean ok = true;
+        for (int i = 0; i < 0xffff; i++) {
+            if (0xd800 <= i && i <= 0xdfff) {
+                // Surrogate pair characters.
+                continue;
+            }
+            ok &= check("char: " + i, String.valueOf((char) i));
+        }
+        // Dangling surrogate pairs. We can't preserve them.
+        assertFalse(check("+ud800", "\ud800"));
+        assertFalse(check("+udc00", "\udc00"));
+
+        for (int i = 0xd800; i < 0xdc00; i ++) {
+            for (int j = 0xdc00; j < 0xe000; j++) {
+                ok &= check("char: " + i, String.valueOf((char) i) + String.valueOf((char) j));
+            }
+        }
+        assertTrue("Some tests failed.  See logcat for details.", ok);
+    }
 }
index c2cc2b9..d5115de 100644 (file)
@@ -28,7 +28,8 @@ interface IMidiDeviceServer
     void closeDevice();
 
     // connects the input port pfd to the specified output port
-    void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
+    // Returns the PID of the called process.
+    int connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
 
     MidiDeviceInfo getDeviceInfo();
     void setDeviceInfo(in MidiDeviceInfo deviceInfo);
index e1990cd..e4588fe 100644 (file)
@@ -19,6 +19,7 @@ package android.media.midi;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -181,9 +182,16 @@ public final class MidiDevice implements Closeable {
         }
          try {
             IBinder token = new Binder();
-            mDeviceServer.connectPorts(token, pfd, outputPortNumber);
-            // close our copy of the file descriptor
-            IoUtils.closeQuietly(pfd);
+            int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
+            // If the service is a different Process then it will duplicate the pfd
+            // and we can safely close this one.
+            // But if the service is in the same Process then closing the pfd will
+            // kill the connection. So don't do that.
+            if (calleePid != Process.myPid()) {
+                // close our copy of the file descriptor
+                IoUtils.closeQuietly(pfd);
+            }
+
             return new MidiConnection(token, inputPort);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in connectPorts");
index 19ff624..f0abf71 100644 (file)
@@ -254,7 +254,7 @@ public final class MidiDeviceServer implements Closeable {
         }
 
         @Override
-        public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
+        public int connectPorts(IBinder token, ParcelFileDescriptor pfd,
                 int outputPortNumber) {
             MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
             MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber];
@@ -270,6 +270,7 @@ public final class MidiDeviceServer implements Closeable {
             synchronized (mPortClients) {
                 mPortClients.put(token, client);
             }
+            return Process.myPid(); // for caller to detect same process ID
         }
 
         @Override
index 5722cb0..39f2a32 100644 (file)
@@ -882,7 +882,7 @@ MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
                 break;
             }
 
-            info.mThumbCompressedSize = image_data.thumbnail_length;
+            info.mThumbCompressedSize = image_data.thumbnail.length;
             info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
             info.mImagePixWidth = image_data.full_width;
             info.mImagePixHeight = image_data.full_height;
@@ -932,19 +932,19 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize)
                     break;
                 }
 
-                if (image_data.thumbnail_length == 0) {
+                if (image_data.thumbnail.length == 0) {
                     // No thumbnail.
                     break;
                 }
 
-                result = malloc(image_data.thumbnail_length);
+                result = malloc(image_data.thumbnail.length);
                 if (result) {
                     piex::Error err = stream.get()->GetData(
-                            image_data.thumbnail_offset,
-                            image_data.thumbnail_length,
+                            image_data.thumbnail.offset,
+                            image_data.thumbnail.length,
                             (std::uint8_t *)result);
                     if (err == piex::Error::kOk) {
-                        outThumbSize = image_data.thumbnail_length;
+                        outThumbSize = image_data.thumbnail.length;
                     } else {
                         free(result);
                     }
diff --git a/packages/DocumentsUI/res/drawable/drag_shadow_background.xml b/packages/DocumentsUI/res/drawable/drag_shadow_background.xml
new file mode 100644 (file)
index 0000000..49465cb
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+  <solid android:color="@color/item_doc_background" />
+  <stroke
+      android:width="1dp"
+      android:color="#ff9f9f9f" />
+  <corners
+      android:bottomRightRadius="3dp"
+      android:bottomLeftRadius="3dp"
+      android:topLeftRadius="3dp"
+      android:topRightRadius="3dp"/>
+</shape>
diff --git a/packages/DocumentsUI/res/layout/drag_shadow_layout.xml b/packages/DocumentsUI/res/layout/drag_shadow_layout.xml
new file mode 100644 (file)
index 0000000..26613ef
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingStart="8dp"
+    android:paddingEnd="8dp"
+    android:orientation="horizontal"
+    android:gravity="center_vertical|left"
+    android:background="@drawable/drag_shadow_background">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/root_icon_size"
+        android:layout_height="@dimen/root_icon_size"
+        android:scaleType="centerInside"
+        android:contentDescription="@null"
+        android:duplicateParentState="true"/>
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:textAlignment="viewStart"
+        android:textColor="@color/item_title"
+        android:paddingStart="8dp"/>
+
+</LinearLayout>
index 5af7da3..e682994 100644 (file)
@@ -38,4 +38,8 @@
     <dimen name="drag_shadow_size">120dp</dimen>
     <dimen name="grid_item_elevation">2dp</dimen>
     <dimen name="max_drawer_width">280dp</dimen>
+
+    <dimen name="drag_shadow_width">160dp</dimen>
+    <dimen name="drag_shadow_height">48dp</dimen>
+
 </resources>
index fb557ca..a1eee3d 100644 (file)
         <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
     </plurals>
 
+    <!-- Label text showing user how many items are being dragged. Can be one or more elements. -->
+    <plurals name="elements_dragged">
+        <item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> item</item>
+        <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> items</item>
+    </plurals>
+
     <!-- Dialog text shown to users when asking if they want to delete a file (a confirmation) -->
     <string name="delete_filename_confirmation_message">Delete \"<xliff:g id="name" example="cat.jpg">%1$s</xliff:g>\"?</string>
     <!-- Dialog text shown to users when asking if they want to delete a folder (a confirmation) -->
index c2bb4eb..630f359 100644 (file)
@@ -40,6 +40,7 @@ import android.content.Loader;
 import android.database.Cursor;
 import android.graphics.Canvas;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -72,8 +73,8 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
-import android.widget.Toolbar;
 import android.widget.TextView;
+import android.widget.Toolbar;
 
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DirectoryLoader;
@@ -1229,41 +1230,68 @@ public class DirectoryFragment extends Fragment
                 DocumentInfo.fromDirectoryCursor(cursor));
     }
 
-    private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
-        if (docs.size() == 1) {
-            final DocumentInfo doc = docs.get(0);
-            return mIconHelper.getDocumentIcon(getActivity(), doc.authority, doc.documentId,
-                    doc.mimeType, doc.icon);
-        }
-        return getActivity().getDrawable(R.drawable.ic_doc_generic);
-    }
+    private static class DragShadowBuilder extends View.DragShadowBuilder {
+
+        private final Context mContext;
+        private final IconHelper mIconHelper;
+        private final LayoutInflater mInflater;
+        private final View mShadowView;
+        private final TextView mTitle;
+        private final ImageView mIcon;
+        private final int mWidth;
+        private final int mHeight;
 
-    private class DrawableShadowBuilder extends View.DragShadowBuilder {
+        public DragShadowBuilder(Context context, IconHelper iconHelper, List<DocumentInfo> docs) {
+            mContext = context;
+            mIconHelper = iconHelper;
+            mInflater = LayoutInflater.from(context);
 
-        private final Drawable mShadow;
+            mWidth = mContext.getResources().getDimensionPixelSize(R.dimen.drag_shadow_width);
+            mHeight= mContext.getResources().getDimensionPixelSize(R.dimen.drag_shadow_height);
 
-        private final int mShadowDimension;
+            mShadowView = mInflater.inflate(R.layout.drag_shadow_layout, null);
+            mTitle = (TextView) mShadowView.findViewById(android.R.id.title);
+            mIcon = (ImageView) mShadowView.findViewById(android.R.id.icon);
 
-        public DrawableShadowBuilder(Drawable shadow) {
-            mShadow = shadow;
-            mShadowDimension = getResources().getDimensionPixelSize(
-                    R.dimen.drag_shadow_size);
-            mShadow.setBounds(0, 0, mShadowDimension, mShadowDimension);
+            mTitle.setText(getTitle(docs));
+            mIcon.setImageDrawable(getIcon(docs));
+        }
+
+        private Drawable getIcon(List<DocumentInfo> docs) {
+            if (docs.size() == 1) {
+                final DocumentInfo doc = docs.get(0);
+                return mIconHelper.getDocumentIcon(mContext, doc.authority, doc.documentId,
+                        doc.mimeType, doc.icon);
+            }
+            return mContext.getDrawable(R.drawable.ic_doc_generic);
+        }
+
+        private String getTitle(List<DocumentInfo> docs) {
+            if (docs.size() == 1) {
+                final DocumentInfo doc = docs.get(0);
+                return doc.displayName;
+            }
+            return Shared.getQuantityString(mContext, R.plurals.elements_dragged, docs.size());
         }
 
         @Override
         public void onProvideShadowMetrics(
                 Point shadowSize, Point shadowTouchPoint) {
-            shadowSize.set(mShadowDimension, mShadowDimension);
-            shadowTouchPoint.set(mShadowDimension / 2, mShadowDimension / 2);
+            shadowSize.set(mWidth, mHeight);
+            shadowTouchPoint.set(mWidth, mHeight);
         }
 
         @Override
         public void onDrawShadow(Canvas canvas) {
-            mShadow.draw(canvas);
+            Rect r = canvas.getClipBounds();
+            // Calling measure is necessary in order for all child views to get correctly laid out.
+            mShadowView.measure(
+                    View.MeasureSpec.makeMeasureSpec(r.right- r.left, View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(r.top- r.bottom, View.MeasureSpec.EXACTLY));
+            mShadowView.layout(r.left, r.top, r.right, r.bottom);
+            mShadowView.draw(canvas);
         }
     }
-
     /**
      * Abstract task providing support for loading documents *off*
      * the main thread. And if it isn't obvious, creating a list
@@ -1414,7 +1442,7 @@ public class DirectoryFragment extends Fragment
                 }
                 v.startDragAndDrop(
                         mClipper.getClipDataForDocuments(docs),
-                        new DrawableShadowBuilder(getDragShadowIcon(docs)),
+                        new DragShadowBuilder(getActivity(), mIconHelper, docs),
                         getDisplayState().stack.peek(),
                         View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
                                 View.DRAG_FLAG_GLOBAL_URI_WRITE
index a87afe0..248d0c0 100644 (file)
                     android:singleLine="true"
                     android:ellipsize="end"
                     android:visibility="visible"
-                    android:inputType="textNoSuggestions">
+                    android:inputType="number"
+                    android:digits="0123456789 ,-">
                 </com.android.printspooler.widget.CustomErrorEditText>
 
             </LinearLayout>
index cde0fa3..e7aebdd 100644 (file)
@@ -62,7 +62,6 @@ import android.printservice.PrintServiceInfo;
 import android.provider.DocumentsContract;
 import android.text.Editable;
 import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
 import android.text.TextWatcher;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -117,8 +116,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
         PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
@@ -165,22 +162,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
     private static final int MIN_COPIES = 1;
     private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES);
 
-    private static final Pattern PATTERN_DIGITS = Pattern.compile("[\\d]+");
-
-    private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile(
-            "(?=[]\\[+&|!(){}^\"~*?:\\\\])");
-
-    private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
-            "[\\s]*[0-9]+[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
-                    + "[\\s]*[0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
-
     private boolean mIsOptionsUiBound = false;
 
     private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
             new PrinterAvailabilityDetector();
 
-    private final SimpleStringSplitter mStringCommaSplitter = new SimpleStringSplitter(',');
-
     private final OnFocusChangeListener mSelectAllOnFocusListener = new SelectAllOnFocusListener();
 
     private PrintSpoolerProvider mSpoolerProvider;
@@ -1493,9 +1479,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
                     cancelPrint();
                 }
             } else if (view == mMoreOptionsButton) {
-                // The selected pages is only applied once the user leaves the text field. A click
-                // on this button, does not count as leaving.
-                updateSelectedPagesFromTextField();
+                if (mPageRangeEditText.getError() == null) {
+                    // The selected pages is only applied once the user leaves the text field. A click
+                    // on this button, does not count as leaving.
+                    updateSelectedPagesFromTextField();
+                }
 
                 if (mCurrentPrinter != null) {
                     startAdvancedPrintOptionsActivity(mCurrentPrinter);
@@ -1918,42 +1906,10 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
         }
 
         if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
-            List<PageRange> pageRanges = new ArrayList<>();
-            mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
-
-            while (mStringCommaSplitter.hasNext()) {
-                String range = mStringCommaSplitter.next().trim();
-                if (TextUtils.isEmpty(range)) {
-                    continue;
-                }
-                final int dashIndex = range.indexOf('-');
-                final int fromIndex;
-                final int toIndex;
-
-                if (dashIndex > 0) {
-                    fromIndex = Integer.parseInt(range.substring(0, dashIndex).trim()) - 1;
-                    // It is possible that the dash is at the end since the input
-                    // verification can has to allow the user to keep entering if
-                    // this would lead to a valid input. So we handle this.
-                    if (dashIndex < range.length() - 1) {
-                        String fromString = range.substring(dashIndex + 1, range.length()).trim();
-                        toIndex = Integer.parseInt(fromString) - 1;
-                    } else {
-                        toIndex = fromIndex;
-                    }
-                } else {
-                    fromIndex = toIndex = Integer.parseInt(range) - 1;
-                }
-
-                PageRange pageRange = new PageRange(Math.min(fromIndex, toIndex),
-                        Math.max(fromIndex, toIndex));
-                pageRanges.add(pageRange);
-            }
-
-            PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
-            pageRanges.toArray(pageRangesArray);
+            PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+            final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
 
-            return PageRangeUtils.normalize(pageRangesArray);
+            return PageRangeUtils.parsePageRanges(mPageRangeEditText.getText(), pageCount);
         }
 
         return PageRange.ALL_PAGES_ARRAY;
@@ -2785,7 +2741,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
                 editText.setSelection(editText.getText().length());
             }
 
-            if (view == mPageRangeEditText && !hasFocus) {
+            if (view == mPageRangeEditText && !hasFocus && mPageRangeEditText.getError() == null) {
                 updateSelectedPagesFromTextField();
             }
         }
@@ -2805,18 +2761,12 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
         @Override
         public void afterTextChanged(Editable editable) {
             final boolean hadErrors = hasErrors();
-            String text = editable.toString();
 
-            if (TextUtils.isEmpty(text)) {
-                if (mPageRangeEditText.getError() == null) {
-                    mPageRangeEditText.setError("");
-                    updateOptionsUi();
-                }
-                return;
-            }
+            PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+            final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
+            PageRange[] ranges = PageRangeUtils.parsePageRanges(editable, pageCount);
 
-            String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
-            if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
+            if (ranges.length == 0) {
                 if (mPageRangeEditText.getError() == null) {
                     mPageRangeEditText.setError("");
                     updateOptionsUi();
@@ -2824,30 +2774,6 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
                 return;
             }
 
-            PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
-            final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
-
-            // The range
-            Matcher matcher = PATTERN_DIGITS.matcher(text);
-            while (matcher.find()) {
-                String numericString = text.substring(matcher.start(), matcher.end()).trim();
-                if (TextUtils.isEmpty(numericString)) {
-                    continue;
-                }
-                final int pageIndex = Integer.parseInt(numericString);
-                if (pageIndex < 1 || pageIndex > pageCount) {
-                    if (mPageRangeEditText.getError() == null) {
-                        mPageRangeEditText.setError("");
-                        updateOptionsUi();
-                    }
-                    return;
-                }
-            }
-
-            // We intentionally do not catch the case of the from page being
-            // greater than the to page. When computing the requested pages
-            // we just swap them if necessary.
-
             if (mPageRangeEditText.getError() != null) {
                 mPageRangeEditText.setError(null);
                 updateOptionsUi();
index cee16c8..fcc9f6a 100644 (file)
@@ -18,12 +18,11 @@ package com.android.printspooler.ui;
 
 import android.app.Activity;
 import android.app.LoaderManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender.SendIntentException;
 import android.content.Loader;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.DataSetObserver;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -34,6 +33,7 @@ import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.ContextMenu;
@@ -80,8 +80,8 @@ public final class SelectPrinterActivity extends Activity implements
 
     private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
 
-    /** If there are any enabled print services */
-    private boolean mHasEnabledPrintServices;
+    /** The currently enabled print services by their ComponentName */
+    private ArrayMap<ComponentName, PrintServiceInfo> mEnabledPrintServices;
 
     private PrinterRegistry mPrinterRegistry;
 
@@ -100,6 +100,8 @@ public final class SelectPrinterActivity extends Activity implements
 
         setContentView(R.layout.select_printer_activity);
 
+        mEnabledPrintServices = new ArrayMap<>();
+
         mPrinterRegistry = new PrinterRegistry(this, null, LOADER_ID_PRINT_REGISTRY,
                 LOADER_ID_PRINT_REGISTRY_INT);
 
@@ -317,7 +319,7 @@ public final class SelectPrinterActivity extends Activity implements
         }
         TextView titleView = (TextView) findViewById(R.id.title);
         View progressBar = findViewById(R.id.progress_bar);
-        if (!mHasEnabledPrintServices) {
+        if (mEnabledPrintServices.size() > 0) {
             titleView.setText(R.string.print_no_print_services);
             progressBar.setVisibility(View.GONE);
         } else if (adapter.getUnfilteredCount() <= 0) {
@@ -346,11 +348,16 @@ public final class SelectPrinterActivity extends Activity implements
 
     @Override
     public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
-            List<PrintServiceInfo> data) {
-        if (data == null || data.isEmpty()) {
-            mHasEnabledPrintServices = false;
-        } else {
-            mHasEnabledPrintServices = true;
+            List<PrintServiceInfo> services) {
+        mEnabledPrintServices.clear();
+
+        if (services != null && !services.isEmpty()) {
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                PrintServiceInfo service = services.get(i);
+
+                mEnabledPrintServices.put(service.getComponentName(), service);
+            }
         }
 
         onPrintServicesUpdate();
@@ -533,14 +540,12 @@ public final class SelectPrinterActivity extends Activity implements
             CharSequence title = printer.getName();
             Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
 
-            CharSequence printServiceLabel;
-            try {
-                PackageInfo packageInfo = getPackageManager().getPackageInfo(
-                        printer.getId().getServiceName().getPackageName(), 0);
+            PrintServiceInfo service = mEnabledPrintServices.get(printer.getId().getServiceName());
 
-                printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
-            } catch (NameNotFoundException e) {
-                printServiceLabel = null;
+            CharSequence printServiceLabel = null;
+            if (service != null) {
+                printServiceLabel = service.getResolveInfo().loadLabel(getPackageManager())
+                        .toString();
             }
 
             CharSequence description = printer.getDescription();
index 2b317b3..7425c03 100644 (file)
@@ -18,7 +18,9 @@ package com.android.printspooler.util;
 
 import android.print.PageRange;
 import android.print.PrintDocumentInfo;
+import android.util.Pair;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 
@@ -155,6 +157,167 @@ public final class PageRangeUtils {
     }
 
     /**
+     * Return the next position after {@code pos} that is not a space character.
+     *
+     * @param s   The string to parse
+     * @param pos The starting position
+     *
+     * @return The position of the first space character
+     */
+    private static int readWhiteSpace(CharSequence s, int pos) {
+        while (pos < s.length() && s.charAt(pos) == ' ') {
+            pos++;
+        }
+
+        return pos;
+    }
+
+    /**
+     * Read a number from a string at a certain position.
+     *
+     * @param s   The string to parse
+     * @param pos The starting position
+     *
+     * @return The position after the number + the number read or null if the number was not found
+     */
+    private static Pair<Integer, Integer> readNumber(CharSequence s, int pos) {
+        Integer result = 0;
+        while (pos < s.length() && s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
+            // Number cannot start with 0
+            if (result == 0 && s.charAt(pos) == '0') {
+                break;
+            }
+            result = result * 10 + (s.charAt(pos) - '0');
+            // Abort on overflow
+            if (result < 0) {
+                break;
+            }
+            pos++;
+        }
+
+        // 0 is not a valid page number
+        if (result == 0) {
+            return new Pair<>(pos, null);
+        } else {
+            return new Pair<>(pos, result);
+        }
+    }
+
+    /**
+     * Read a single character from a string at a certain position.
+     *
+     * @param s            The string to parse
+     * @param pos          The starting position
+     * @param expectedChar The character to read
+     *
+     * @return The position after the character + the character read or null if the character was
+     *         not found
+     */
+    private static Pair<Integer, Character> readChar(CharSequence s, int pos, char expectedChar) {
+        if (pos < s.length() && s.charAt(pos) == expectedChar) {
+            return new Pair<>(pos + 1, expectedChar);
+        } else {
+            return new Pair<>(pos, null);
+        }
+    }
+
+    /**
+     * Read a page range character from a string at a certain position.
+     *
+     * @param s             The string to parse
+     * @param pos           The starting position
+     * @param maxPageNumber The highest page number to accept.
+     *
+     * @return The position after the page range + the page range read or null if the page range was
+     *         not found
+     */
+    private static Pair<Integer, PageRange> readRange(CharSequence s, int pos, int maxPageNumber) {
+        Pair<Integer, Integer> retInt;
+        Pair<Integer, Character> retChar;
+
+        Character comma;
+        if (pos == 0) {
+            // When we reading the first range, we do not want to have a comma
+            comma = ',';
+        } else {
+            retChar = readChar(s, pos, ',');
+            pos = retChar.first;
+            comma = retChar.second;
+        }
+
+        pos = readWhiteSpace(s, pos);
+
+        retInt = readNumber(s, pos);
+        pos = retInt.first;
+        Integer start = retInt.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        retChar = readChar(s, pos, '-');
+        pos = retChar.first;
+        Character separator = retChar.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        retInt = readNumber(s, pos);
+        pos = retInt.first;
+        Integer end = retInt.second;
+
+        pos = readWhiteSpace(s, pos);
+
+        if (comma != null &&
+                // range, maybe unbounded
+                ((separator != null && (start != null || end != null)) ||
+                        // single page
+                        (separator == null && start != null && end == null))) {
+            if (start == null) {
+                start = 1;
+            }
+
+            if (end == null) {
+                if (separator == null) {
+                    end = start;
+                } else {
+                    end = maxPageNumber;
+                }
+            }
+
+            if (start <= end && start >= 1 && end <= maxPageNumber) {
+                return new Pair<>(pos, new PageRange(start - 1, end - 1));
+            }
+        }
+
+        return new Pair<>(pos, null);
+    }
+
+    /**
+     * Parse a string into an array of page ranges.
+     *
+     * @param s             The string to parse
+     * @param maxPageNumber The highest page number to accept.
+     *
+     * @return The parsed ranges or null if the string could not be parsed.
+     */
+    public static PageRange[] parsePageRanges(CharSequence s, int maxPageNumber) {
+        ArrayList<PageRange> ranges = new ArrayList<>();
+
+        int pos = 0;
+        while (pos < s.length()) {
+            Pair<Integer, PageRange> retRange = readRange(s, pos, maxPageNumber);
+
+            if (retRange.second == null) {
+                ranges.clear();
+                break;
+            }
+
+            ranges.add(retRange.second);
+            pos = retRange.first;
+        }
+
+        return PageRangeUtils.normalize(ranges.toArray(new PageRange[ranges.size()]));
+    }
+
+    /**
      * Offsets a the start and end of page ranges with the given value.
      *
      * @param pageRanges The page ranges to offset.
index 9839446..7222cff 100644 (file)
             android:name="com.android.systemui.tv.pip.PipOverlayActivity"
             android:exported="true"
             android:theme="@style/PipTheme"
-            android:launchMode="singleTop"
             android:taskAffinity=""
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
             android:resizeableActivity="true"
index 86fda0d..186a4ba 100644 (file)
     <item android:state_focused="true">
         <layer-list>
             <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_close_white" />
+            <item android:drawable="@drawable/ic_close_white"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_close_white"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
         </layer-list>
     </item>
-    <item android:drawable="@drawable/ic_close_white" />
 </selector>
index 332c669..c48dc82 100644 (file)
     <item android:state_focused="true">
         <layer-list>
             <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
+            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
         </layer-list>
     </item>
-    <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
 </selector>
index d277b07..bcc8973 100644 (file)
     <item android:state_focused="true">
         <layer-list>
             <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_pause_white_24dp" />
+            <item android:drawable="@drawable/ic_pause_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_pause_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
         </layer-list>
     </item>
-    <item android:drawable="@drawable/ic_pause_white_24dp" />
 </selector>
index fecdc09..f77ea1d 100644 (file)
     <item android:state_focused="true">
         <layer-list>
             <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
+                android:top="@dimen/tv_pip_button_icon_padding"
+                android:bottom="@dimen/tv_pip_button_icon_padding"
+                android:left="@dimen/tv_pip_button_icon_padding"
+                android:right="@dimen/tv_pip_button_icon_padding" />
         </layer-list>
     </item>
-    <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
 </selector>
index f1be672..c5398a2 100644 (file)
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početak"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni ekrani"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
-    <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
-    <skip />
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obavještenja"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Skracenice tastature"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promijeni način unosa"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoć"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Preglednik"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
index 7c2da10..322197e 100644 (file)
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"میان‌برهای صفحه‌کلید"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تغییر روش ورودی"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"برنامه‌ها"</string>
-    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"همیار"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"دستیار"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"مرورگر"</string>
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"مخاطبین"</string>
     <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"رایانامه"</string>
index c8f6649..45c3626 100644 (file)
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
-    <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
-    <skip />
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacións"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atallos de teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar de método de entrada"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacións"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistente"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar cos controis de volume"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non molestar"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Atallo dos botóns de volume"</string>
index 220250b..eed5f36 100644 (file)
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten forblir låst til du låser den opp manuelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Motta varsler raskere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem før du låser opp"</string>
-    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nei, takk"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nei takk"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Konfigurer"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="3179845345429841822">"Avslutt nå"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
     <string name="screen_pinning_description" msgid="3577937698406151604">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk og hold inne Tilbake for å låse opp."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
-    <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string>
+    <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igjen neste gang du slår den på i innstillingene."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
index 0e818c4..81d0456 100644 (file)
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ecran de pornire"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recente"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Înapoi"</string>
-    <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
-    <skip />
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificări"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Comenzi rapide de la tastatură"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Comutați metoda de introducere a textului"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicații"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistent"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Agendă"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzică"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afișează cu comenzile de volum"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nu deranja"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Comandă rapidă din butoanele de volum"</string>
index 1baa67d..86f0ec4 100644 (file)
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Главный экран"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавние"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
-    <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
-    <skip />
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Уведомления"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Быстрые клавиши"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Сменить способ ввода"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Приложения"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помощник"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузер"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакты"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Эл. почта"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Чат"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка."</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календарь"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показывать при нажатии кнопок регулировки громкости"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не беспокоить"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки регулировки громкости"</string>
index d559344..a25b9f1 100644 (file)
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。节电助手已开启。"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。省电模式已开启。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支持USB充电功能。\n只能使用随附的充电器充电。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
-    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要开启节电助手吗?"</string>
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"要开启省电模式吗?"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"开启"</string>
-    <string name="battery_saver_start_action" msgid="5576697451677486320">"开启节电助手"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"开启省电模式"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自动旋转屏幕"</string>
     <string name="user_remove_user_title" msgid="4681256956076895559">"是否移除用户?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"此用户的所有应用和数据均将被删除。"</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
-    <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已开启"</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"省电模式已开启"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
-    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭节电助手"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭省电模式"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"确认设置"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"部分颜色设置可能会导致此设备无法使用。请点击“确定”确认这些颜色设置,否则,系统将在 10 秒后重置这些设置。"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"电池使用情况"</string>
-    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用节电助手"</string>
-    <string name="battery_detail_switch_title" msgid="6285872470260795421">"节电助手"</string>
+    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用省电模式"</string>
+    <string name="battery_detail_switch_title" msgid="6285872470260795421">"省电模式"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
     <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string>
     <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
-    <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
-    <skip />
-    <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
-    <skip />
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+    <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"键盘快捷键"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切换输入法"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"应用"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"辅助应用"</string>
+    <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"浏览器"</string>
+    <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"通讯录"</string>
+    <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"电子邮件"</string>
+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即时通讯"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音乐"</string>
+    <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日历"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"与音量控件一起显示"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"请勿打扰"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按钮快捷键"</string>
index 337513d..4e6a4b1 100644 (file)
@@ -54,5 +54,7 @@
 
     <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
     <dimen name="tv_pip_bounds_space">3dp</dimen>
+    <!-- Extra space around the PIP control button icon to match with the focused circle -->
+    <dimen name="tv_pip_button_icon_padding">5dp</dimen>
 
 </resources>
index 483f9e5..f9f851a 100644 (file)
@@ -53,7 +53,6 @@ import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.tv.animations.FocusAnimationHolder;
 import com.android.systemui.recents.tv.views.RecentsTvView;
 import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -79,7 +78,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
     private boolean mIgnoreAltTabRelease;
 
     private RecentsTvView mRecentsView;
-    private FocusAnimationHolder mRecentsFocusAnimationHolder;
     private View mPipView;
     private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
     private FinishRecentsRunnable mFinishLaunchHomeRunnable;
@@ -133,13 +131,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
             new View.OnFocusChangeListener() {
                 @Override
                 public void onFocusChange(View v, boolean hasFocus) {
-                    if (hasFocus) {
-                        mRecentsFocusAnimationHolder.startFocusLoseAnimation();
-                        mPipRecentsOverlayManager.requestFocus(
-                                mTaskStackViewAdapter.getItemCount() > 0);
-                    } else {
-                        mRecentsFocusAnimationHolder.startFocusGainAnimation();
-                    }
+                    handlePipViewFocusChange(hasFocus);
                 }
             };
 
@@ -288,11 +280,10 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-        mRecentsFocusAnimationHolder = new FocusAnimationHolder(mRecentsView);
 
         mPipView = findViewById(R.id.pip);
         // Place mPipView at the PIP bounds for fine tuned focus handling.
-        Rect pipBounds = mPipManager.getPipBounds();
+        Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
         LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
         lp.width = pipBounds.width();
         lp.height = pipBounds.height();
@@ -513,11 +504,30 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
         if (mPipManager.isPipShown()) {
             mPipView.setVisibility(View.VISIBLE);
             mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
-            mPipView.requestFocus();
+            if (mPipView.hasFocus()) {
+                // This can happen only if the activity is resumed. Ask for reset.
+                handlePipViewFocusChange(true);
+            } else {
+                mPipView.requestFocus();
+            }
         } else {
             mPipView.setVisibility(View.GONE);
             mPipRecentsOverlayManager.removePipRecentsOverlayView();
-            mRecentsFocusAnimationHolder.reset();
+        }
+    }
+
+    /**
+     * Handles the PIP view's focus change.
+     * This starts the relevant recents row animation
+     * and give focus to the recents overlay if needed.
+     */
+    private void handlePipViewFocusChange(boolean hasFocus) {
+        mRecentsView.startRecentsRowFocusAnimation(!hasFocus);
+        if (hasFocus) {
+            // When PIP view has focus, recents overlay view will takes the focus
+            // as if it's the part of the Recents UI.
+            mPipRecentsOverlayManager.requestFocus(
+                    mTaskStackViewAdapter.getItemCount() > 0);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
deleted file mode 100644 (file)
index 864540c..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-package com.android.systemui.recents.tv.animations;
-
-import android.content.res.Resources;
-import android.view.View;
-
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.tv.views.TaskCardView;
-
-/**
- * Collections of Recents row's animation depending on the PIP's focus.
- */
-public class FocusAnimationHolder {
-    private final float DIM_ALPHA = 0.5f;
-
-    private View mRecentsRowView;
-    private int mCardYDelta;
-    private long mDuration;
-
-    public FocusAnimationHolder(View recentsRowView) {
-        mRecentsRowView = recentsRowView;
-
-        Resources res = recentsRowView.getResources();
-        mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
-        mDuration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
-    }
-
-    public void startFocusGainAnimation() {
-        mRecentsRowView.animate()
-                .setDuration(mDuration)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .alpha(1f)
-                .translationY(0);
-    }
-
-    public void startFocusLoseAnimation() {
-        mRecentsRowView.animate()
-                .setDuration(mDuration)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .alpha(DIM_ALPHA)
-                .translationY(mCardYDelta);
-    }
-
-    public void reset() {
-        mRecentsRowView.setTransitionAlpha(1f);
-        mRecentsRowView.setTranslationY(0);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
new file mode 100644 (file)
index 0000000..28abc34
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+package com.android.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * Recents row's focus animation with PIP controls.
+ */
+public class RecentsRowFocusAnimationHolder {
+    private static final float DIM_ALPHA = 0.5f;
+
+    private View mView;
+    private View mTitleView;
+
+    private AnimatorSet mFocusGainAnimatorSet;
+    private AnimatorSet mFocusLoseAnimatorSet;
+
+    public RecentsRowFocusAnimationHolder(View view, View titleView) {
+        mView = view;
+        mTitleView = titleView;
+
+        Resources res = view.getResources();
+        int duration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+
+        mFocusGainAnimatorSet = new AnimatorSet();
+        mFocusGainAnimatorSet.playTogether(
+                ObjectAnimator.ofFloat(mView, "alpha", 1f),
+                ObjectAnimator.ofFloat(mTitleView, "alpha", 1f));
+        mFocusGainAnimatorSet.setDuration(duration);
+        mFocusGainAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+
+        mFocusLoseAnimatorSet = new AnimatorSet();
+        mFocusLoseAnimatorSet.playTogether(
+                ObjectAnimator.ofFloat(mView, "alpha", DIM_ALPHA),
+                ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
+        mFocusLoseAnimatorSet.setDuration(duration);
+        mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+    }
+
+    /**
+     * Returns the Recents row's focus change animation.
+     */
+    public Animator getFocusChangeAnimator(boolean hasFocus) {
+        return hasFocus ? mFocusGainAnimatorSet : mFocusLoseAnimatorSet;
+    }
+
+    /**
+     * Resets the views to the initial state immediately.
+     */
+    public void reset() {
+        mView.setAlpha(1f);
+        mTitleView.setAlpha(1f);
+    }
+}
index d966614..9da8eed 100644 (file)
@@ -37,6 +37,7 @@ import com.android.systemui.recents.events.component.RecentsVisibilityChangedEve
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -52,6 +53,7 @@ public class RecentsTvView extends FrameLayout {
     private TaskStack mStack;
     private TaskStackHorizontalGridView mTaskStackHorizontalView;
     private View mEmptyView;
+    private RecentsRowFocusAnimationHolder mEmptyViewFocusAnimationHolder;
     private boolean mAwaitingFirstLayout = true;
     private Rect mSystemInsets = new Rect();
     private RecentsTvTransitionHelper mTransitionHelper;
@@ -77,6 +79,8 @@ public class RecentsTvView extends FrameLayout {
         LayoutInflater inflater = LayoutInflater.from(context);
         mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
+        mEmptyViewFocusAnimationHolder = new RecentsRowFocusAnimationHolder(mEmptyView, null);
+
         mHandler = new Handler();
         mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
     }
@@ -94,7 +98,6 @@ public class RecentsTvView extends FrameLayout {
             mTaskStackHorizontalView.setStack(stack);
         }
 
-
         if (stack.getStackTaskCount() > 0) {
             hideEmptyView();
         } else {
@@ -134,33 +137,40 @@ public class RecentsTvView extends FrameLayout {
     public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
         if (mTaskStackHorizontalView != null) {
             // Iterate the stack views and try and find the given task.
-            List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
-            int taskViewCount = taskViews.size();
-            for (int j = 0; j < taskViewCount; j++) {
-                TaskCardView tv = taskViews.get(j);
-                if (tv.getTask() == task) {
-                    SystemServicesProxy ssp = Recents.getSystemServices();
-                    ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
-                    return true;
-                }
+            if (mTaskStackHorizontalView.getChildViewForTask(task) != null) {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
+                return true;
             }
         }
         return false;
     }
 
     /**
+     * Starts the focus change animation.
+     */
+    public void startRecentsRowFocusAnimation(boolean hasFocus) {
+        if (mEmptyView.getVisibility() == View.VISIBLE) {
+            mEmptyViewFocusAnimationHolder.getFocusChangeAnimator(hasFocus).start();
+        } else {
+            mTaskStackHorizontalView.startRecentsRowFocusAnimation(hasFocus);
+        }
+    }
+
+    /**
      * Hides the task stack and shows the empty view.
      */
     public void showEmptyView() {
         mEmptyView.setVisibility(View.VISIBLE);
-        mEmptyView.bringToFront();
+        mTaskStackHorizontalView.setVisibility(View.GONE);
     }
 
     /**
      * Shows the task stack and hides the empty view.
      */
     public void hideEmptyView() {
-        mEmptyView.setVisibility(View.INVISIBLE);
+        mEmptyView.setVisibility(View.GONE);
+        mTaskStackHorizontalView.setVisibility(View.VISIBLE);
     }
 
     /**
index 3343aec..d605748 100644 (file)
@@ -24,6 +24,7 @@ import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.KeyEvent;
+import android.view.View;
 import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -31,6 +32,7 @@ import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.tv.animations.DismissAnimationsHolder;
+import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
 import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
 import com.android.systemui.recents.model.Task;
 
@@ -44,6 +46,7 @@ public class TaskCardView extends LinearLayout {
 
     private ViewFocusAnimator mViewFocusAnimator;
     private DismissAnimationsHolder mDismissAnimationsHolder;
+    private RecentsRowFocusAnimationHolder mRecentsRowFocusAnimationHolder;
 
     public TaskCardView(Context context) {
         this(context, null);
@@ -65,6 +68,8 @@ public class TaskCardView extends LinearLayout {
         mTitleTextView = (TextView) findViewById(R.id.card_title_text);
         mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
         mDismissAnimationsHolder = new DismissAnimationsHolder(this);
+        View title = findViewById(R.id.card_info_field);
+        mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
     }
 
     public void init(Task task) {
@@ -193,6 +198,10 @@ public class TaskCardView extends LinearLayout {
         mDismissAnimationsHolder.startDismissAnimation(listener);
     }
 
+    public RecentsRowFocusAnimationHolder getRecentsRowFocusAnimationHolder() {
+        return mRecentsRowFocusAnimationHolder;
+    }
+
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
index 5eb9fda..603721a 100644 (file)
  */
 package com.android.systemui.recents.tv.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
 import android.support.v17.leanback.widget.HorizontalGridView;
 import android.util.AttributeSet;
 import android.view.View;
@@ -36,10 +40,19 @@ import java.util.List;
  * Horizontal Grid View Implementation to show the Task Stack for TV.
  */
 public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
-
+    private static final int ANIMATION_DELAY_MS = 50;
+    private static final int MSG_START_RECENT_ROW_FOCUS_ANIMATION = 100;
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_START_RECENT_ROW_FOCUS_ANIMATION) {
+                startRecentsRowFocusAnimation(msg.arg1 == 1);
+            }
+        }
+    };
     private TaskStack mStack;
-    private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
     private Task mFocusedTask;
+    private AnimatorSet mRecentsRowFocusAnimation;
 
     public TaskStackHorizontalGridView(Context context) {
         this(context, null);
@@ -62,10 +75,18 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
         super.onDetachedFromWindow();
         EventBus.getDefault().unregister(this);
     }
+
     /**
      * Resets this view for reuse.
      */
     public void reset() {
+        for (int i = 0; i < getChildCount(); i++) {
+            ((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder().reset();
+        }
+        if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
+            mRecentsRowFocusAnimation.cancel();
+        }
+        mHandler.removeCallbacksAndMessages(null);
         requestLayout();
     }
 
@@ -119,10 +140,8 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
      * @return Child view for given task
      */
     public TaskCardView getChildViewForTask(Task task) {
-        List<TaskCardView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskCardView tv = taskViews.get(i);
+        for (int i = 0; i < getChildCount(); i++) {
+            TaskCardView tv = (TaskCardView) getChildAt(i);
             if (tv.getTask() == task) {
                 return tv;
             }
@@ -130,12 +149,36 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
         return null;
     }
 
-    public List<TaskCardView> getTaskViews() {
-        return mTaskViews;
+    /**
+     * Starts the focus change animation.
+     */
+    public void startRecentsRowFocusAnimation(final boolean hasFocus) {
+        if (getChildCount() == 0) {
+            // Animation request may happen before view is attached.
+            // Post again with small dealy so animation can be run again later.
+            if (getAdapter().getItemCount() > 0) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                        MSG_START_RECENT_ROW_FOCUS_ANIMATION, hasFocus ? 1 : 0),
+                        ANIMATION_DELAY_MS);
+            }
+            return;
+        }
+        if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
+            mRecentsRowFocusAnimation.cancel();
+        }
+        Animator animator = ((TaskCardView) getChildAt(0)).getRecentsRowFocusAnimationHolder()
+                .getFocusChangeAnimator(hasFocus);
+        mRecentsRowFocusAnimation = new AnimatorSet();
+        AnimatorSet.Builder builder = mRecentsRowFocusAnimation.play(animator);
+        for (int i = 1; i < getChildCount(); i++) {
+            builder.with(((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder()
+                    .getFocusChangeAnimator(hasFocus));
+        }
+        mRecentsRowFocusAnimation.start();
     }
 
     @Override
-    public void onStackTaskAdded(TaskStack stack, Task newTask){
+    public void onStackTaskAdded(TaskStack stack, Task newTask) {
         getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
     }
 
index 601d910..3005535 100644 (file)
@@ -240,16 +240,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         EventBus.getDefault().register(this);
-        getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
-
-            @Override
-            public void onGlobalLayout() {
-                getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
-                        mHandle.getLeft() + mHandle.getWidth(),
-                        mHandle.getTop() + mHandle.getHeight()));
-            }
-        });
     }
 
     @Override
@@ -274,6 +264,15 @@ public class DividerView extends FrameLayout implements OnTouchListener,
         return super.onApplyWindowInsets(insets);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (changed) {
+            mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
+                    mHandle.getRight(), mHandle.getBottom()));
+        }
+    }
+
     public void setWindowManager(DividerWindowManager windowManager) {
         mWindowManager = windowManager;
     }
index b5c1f57..fe54090 100644 (file)
@@ -265,11 +265,7 @@ public class PipManager {
      */
     private void showPipOverlay() {
         if (DEBUG) Log.d(TAG, "showPipOverlay()");
-        Intent intent = new Intent(mContext, PipOverlayActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchStackId(PINNED_STACK_ID);
-        mContext.startActivity(intent, options.toBundle());
+        PipOverlayActivity.showPipOverlay(mContext);
     }
 
     /**
@@ -635,7 +631,7 @@ public class PipManager {
         void onPipActivityClosed();
         /** Invoked when the PIP menu gets shown. */
         void onShowPipMenu();
-        /** Invoked when the PIPed activity is returned back to the fullscreen. */
+        /** Invoked when the PIPed activity is about to return back to the fullscreen. */
         void onMoveToFullscreen();
         /** Invoked when we are above to start resizing the Pip. */
         void onPipResizeAboutToStart();
index c54e73a..854e09d 100644 (file)
@@ -30,6 +30,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
     private final PipManager mPipManager = PipManager.getInstance();
 
     private PipControlsView mPipControlsView;
+    private boolean mRestorePipSizeWhenClose;
 
     @Override
     protected void onCreate(Bundle bundle) {
@@ -38,12 +39,21 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
         mPipManager.addListener(this);
 
         mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+        mRestorePipSizeWhenClose = true;
+    }
+
+    private void restorePipAndFinish() {
+        if (mRestorePipSizeWhenClose) {
+            // When PIP menu activity is closed, restore to the default position.
+            mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+        }
+        finish();
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        finish();
+        restorePipAndFinish();
     }
 
     @Override
@@ -55,6 +65,11 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
     }
 
     @Override
+    public void onBackPressed() {
+        restorePipAndFinish();
+    }
+
+    @Override
     public void onPipEntered() { }
 
     @Override
@@ -67,6 +82,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
 
     @Override
     public void onMoveToFullscreen() {
+        // Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
+        // This conflicts with restoring PIP position, so disable it.
+        mRestorePipSizeWhenClose = false;
         finish();
     }
 
index 5472ad6..e205ff5 100644 (file)
@@ -35,6 +35,14 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 public class PipOverlayActivity extends Activity implements PipManager.Listener {
     private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
 
+    /**
+     * A flag to ensure the single instance of PipOverlayActivity to prevent it from restarting.
+     * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is
+     * restarted. It's because the activity may be started by the Launcher or an intent again,
+     * but we don't want do so for the PipOverlayActivity.
+     */
+    private static boolean sActivityCreated;
+
     private final PipManager mPipManager = PipManager.getInstance();
     private final Handler mHandler = new Handler();
     private View mGuideOverlayView;
@@ -46,9 +54,23 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener
         }
     };
 
+    /**
+     * Shows PIP overlay UI only if it's not there.
+     */
+    static void showPipOverlay(Context context) {
+        if (!sActivityCreated) {
+            Intent intent = new Intent(context, PipOverlayActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            final ActivityOptions options = ActivityOptions.makeBasic();
+            options.setLaunchStackId(PINNED_STACK_ID);
+            context.startActivity(intent, options.toBundle());
+        }
+    }
+
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
+        sActivityCreated = true;
         setContentView(R.layout.tv_pip_overlay);
         mGuideOverlayView = findViewById(R.id.guide_overlay);
         mPipManager.addListener(this);
@@ -71,6 +93,7 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener
     @Override
     protected void onDestroy() {
         super.onDestroy();
+        sActivityCreated = false;
         mHandler.removeCallbacksAndMessages(null);
         mPipManager.removeListener(this);
         mPipManager.resumePipResizing(
index b90b727..47cd8e5 100644 (file)
@@ -131,9 +131,9 @@ public class PipRecentsOverlayManager {
      * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
      * is focused.
      * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
-     * @param hasRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
+     * @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
      */
-    public void requestFocus(boolean hasRecentsFocusable) {
+    public void requestFocus(boolean allowRecentsFocusable) {
         if (!mIsRecentsShown || mIsPipFocusedInRecent) {
             return;
         }
@@ -143,7 +143,7 @@ public class PipRecentsOverlayManager {
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
         mPipControlsView.requestFocus();
         mPipControlsView.startFocusGainAnimation();
-        mRecentsView.setVisibility(hasRecentsFocusable ? View.VISIBLE : View.GONE);
+        mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
     }
 
     /**
index 6a81659..a30f507 100644 (file)
@@ -198,7 +198,7 @@ public class TileLifecycleManagerTests extends AndroidTestCase {
     }
 
     private void waitForCallback(String callback) {
-        for (int i = 0; i < 25; i++) {
+        for (int i = 0; i < 50; i++) {
             if (mCallbacks.contains(callback)) {
                 mCallbacks.remove(callback);
                 return;
@@ -229,7 +229,7 @@ public class TileLifecycleManagerTests extends AndroidTestCase {
                 }
             });
             try {
-                lock.wait(5000);
+                lock.wait(10000);
             } catch (InterruptedException e) {
             }
         }
index 1b0d3ac..f93fb1b 100644 (file)
@@ -596,27 +596,28 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         }
         final boolean showBadge;
         final Intent onClickIntent;
-        if (provider.maskedBySuspendedPackage) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (provider.maskedBySuspendedPackage) {
                 UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
                 showBadge = userInfo.isManagedProfile();
                 onClickIntent = mDevicePolicyManagerInternal.createPackageSuspendedDialogIntent(
                         providerPackage, providerUserId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        } else if (provider.maskedByQuietProfile) {
-            showBadge = true;
-            onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
-                    providerUserId);
-        } else /* provider.maskedByLockedProfile */ {
-            showBadge = true;
-            onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
-                    providerUserId);
-            if (onClickIntent != null) {
-                onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            } else if (provider.maskedByQuietProfile) {
+                showBadge = true;
+                onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
+                        providerUserId);
+            } else /* provider.maskedByLockedProfile */ {
+                showBadge = true;
+                onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
+                        providerUserId);
+                if (onClickIntent != null) {
+                    onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK
+                            | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                }
             }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
 
         for (int j = 0; j < widgetCount; j++) {
index 377a9e2..0a2153e 100644 (file)
@@ -979,6 +979,7 @@ public class AppOpsService extends IAppOpsService.Stub {
                 usageRestrictions.put(usage, r);
             }
         }
+        notifyWatchersOfChange(code);
     }
 
     @Override
@@ -2284,6 +2285,10 @@ public class AppOpsService extends IAppOpsService.Stub {
             pruneUserRestrictionsForToken(token, userHandle);
         }
 
+        notifyWatchersOfChange(code);
+    }
+
+    private void notifyWatchersOfChange(int code) {
         final ArrayList<Callback> clonedCallbacks;
         synchronized (this) {
             ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
index a4d6be5..82a36b4 100644 (file)
@@ -4134,8 +4134,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
 //        }
         updateTcpBufferSizes(networkAgent);
 
-        final boolean flushDns = updateRoutes(newLp, oldLp, netId);
-        updateDnses(newLp, oldLp, netId, flushDns);
+        updateRoutes(newLp, oldLp, netId);
+        updateDnses(newLp, oldLp, netId);
 
         updateClat(newLp, oldLp, networkAgent);
         if (isDefaultNetwork(networkAgent)) {
@@ -4238,30 +4238,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
         return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
     }
 
-    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,
-                             boolean flush) {
-        if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
-            Collection<InetAddress> dnses = newLp.getDnsServers();
-            if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
-            try {
-                mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
-                    newLp.getDomains());
-            } catch (Exception e) {
-                loge("Exception in setDnsServersForNetwork: " + e);
-            }
-            final NetworkAgentInfo defaultNai = getDefaultNetwork();
-            if (defaultNai != null && defaultNai.network.netId == netId) {
-                setDefaultDnsSystemProperties(dnses);
-            }
-            flushVmDnsCache();
-        } else if (flush) {
-            try {
-                mNetd.flushNetworkDnsCache(netId);
-            } catch (Exception e) {
-                loge("Exception in flushNetworkDnsCache: " + e);
-            }
-            flushVmDnsCache();
+    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+        if (oldLp != null && newLp.isIdenticalDnses(oldLp)) {
+            return;  // no updating necessary
+        }
+
+        Collection<InetAddress> dnses = newLp.getDnsServers();
+        if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
+        try {
+            mNetd.setDnsServersForNetwork(
+                    netId, NetworkUtils.makeStrings(dnses), newLp.getDomains());
+        } catch (Exception e) {
+            loge("Exception in setDnsServersForNetwork: " + e);
+        }
+        final NetworkAgentInfo defaultNai = getDefaultNetwork();
+        if (defaultNai != null && defaultNai.network.netId == netId) {
+            setDefaultDnsSystemProperties(dnses);
         }
+        flushVmDnsCache();
     }
 
     private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
index c6d536d..bf4df94 100644 (file)
@@ -1937,16 +1937,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     @Override
-    public void flushNetworkDnsCache(int netId) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "flushnet", netId);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
     public void setFirewallEnabled(boolean enabled) {
         enforceSystemUid();
         try {
index 660f790..99c41ea 100644 (file)
@@ -2897,9 +2897,10 @@ public class NotificationManagerService extends SystemService {
     }
 
     private void scheduleSendRankingUpdate() {
-        mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
-        Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
-        mHandler.sendMessage(m);
+        if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
+            Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
+            mHandler.sendMessage(m);
+        }
     }
 
     private void handleSendRankingUpdate() {
index f85dce7..83ddf1c 100644 (file)
@@ -7014,6 +7014,15 @@ public class PackageManagerService extends IPackageManager.Stub {
                 Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
             }
 
+            if (!isFirstBoot()) {
+                try {
+                    ActivityManagerNative.getDefault().showBootMessage(
+                            mContext.getResources().getString(R.string.android_upgrading_apk,
+                                    curr, total), true);
+                } catch (RemoteException e) {
+                }
+            }
+
             if (PackageDexOptimizer.canOptimizePackage(pkg)) {
                 // If the cache was pruned, any compiled odex files will likely be out of date
                 // and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
index eba7818..08d9ddf 100644 (file)
@@ -10625,7 +10625,10 @@ public class WindowManagerService extends IWindowManager.Stub
     @Override
     public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
         try {
-            getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
+            WindowState focusedWindow = getFocusedWindow();
+            if (focusedWindow != null && focusedWindow.mClient != null) {
+                getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
+            }
         } catch (RemoteException e) {
         }
     }
index 0d4887d..1d8c123 100644 (file)
@@ -4357,6 +4357,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         }
     }
 
+    /**
+     * @return {@code true} if the package is installed and set as always-on, {@code false} if it is
+     * not installed and therefore not available.
+     *
+     * @throws SecurityException if the caller is not a profile or device owner.
+     * @throws UnsupportedException if the package does not support being set as always-on.
+     */
     @Override
     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage)
             throws SecurityException {
@@ -4366,13 +4373,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
-        try{
+        try {
+            if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
+                return false;
+            }
             ConnectivityManager connectivityManager = (ConnectivityManager)
                     mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            return connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage);
+            if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage)) {
+                throw new UnsupportedOperationException();
+            }
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
+        return true;
     }
 
     @Override