diff options
43 files changed, 861 insertions, 282 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 0bcee86be7d8..8ccd5d2ebcba 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1598,10 +1598,10 @@ public class Am extends BaseCommand { } System.out.println("Performing idle maintenance..."); - Intent intent = new Intent( - "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"); - mAm.broadcastIntent(null, intent, null, null, 0, null, null, null, - android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL); + try { + mAm.sendIdleJobTrigger(); + } catch (RemoteException e) { + } } private void runScreenCompat() throws Exception { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1a7c7467633f..6b628370ba28 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1527,7 +1527,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case SET_LOCK_SCREEN_SHOWN_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - setLockScreenShown(data.readInt() != 0); + final boolean showing = data.readInt() != 0; + final boolean occluded = data.readInt() != 0; + setLockScreenShown(showing, occluded); reply.writeNoException(); return true; } @@ -2968,6 +2970,12 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + case SEND_IDLE_JOB_TRIGGER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + sendIdleJobTrigger(); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -4922,12 +4930,13 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return pfd; } - public void setLockScreenShown(boolean shown) throws RemoteException + public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(shown ? 1 : 0); + data.writeInt(showing ? 1 : 0); + data.writeInt(occluded ? 1 : 0); mRemote.transact(SET_LOCK_SCREEN_SHOWN_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -6244,6 +6253,16 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public void sendIdleJobTrigger() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(SEND_IDLE_JOB_TRIGGER_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken, IActivityContainerCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 783c37de1552..c62c1115fe81 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -105,7 +105,7 @@ public class AppOpsManager { // when adding one of these: // - increment _NUM_OP - // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode + // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpToPerms, sOpDefault // - add descriptive strings to Settings/res/values/arrays.xml // - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app) @@ -339,6 +339,43 @@ public class AppOpsManager { public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; + private static final int[] RUNTIME_PERMISSIONS_OPS = { + // Contacts + OP_READ_CONTACTS, + OP_WRITE_CONTACTS, + OP_GET_ACCOUNTS, + // Calendar + OP_READ_CALENDAR, + OP_WRITE_CALENDAR, + // SMS + OP_SEND_SMS, + OP_RECEIVE_SMS, + OP_READ_SMS, + OP_RECEIVE_WAP_PUSH, + OP_RECEIVE_MMS, + OP_READ_CELL_BROADCASTS, + // Storage + OP_READ_EXTERNAL_STORAGE, + OP_WRITE_EXTERNAL_STORAGE, + // Location + OP_COARSE_LOCATION, + OP_FINE_LOCATION, + // Phone + OP_READ_PHONE_STATE, + OP_CALL_PHONE, + OP_READ_CALL_LOG, + OP_WRITE_CALL_LOG, + OP_ADD_VOICEMAIL, + OP_USE_SIP, + OP_PROCESS_OUTGOING_CALLS, + // Microphone + OP_RECORD_AUDIO, + // Camera + OP_CAMERA, + // Body sensors + OP_BODY_SENSORS + }; + /** * This maps each operation to the operation that serves as the * switch to determine whether it is allowed. Generally this is @@ -922,7 +959,7 @@ public class AppOpsManager { /** * Mapping from a permission to the corresponding app op. */ - private static HashMap<String, Integer> sPermToOp = new HashMap<>(); + private static HashMap<String, Integer> sRuntimePermToOp = new HashMap<>(); static { if (sOpToSwitch.length != _NUM_OP) { @@ -962,9 +999,9 @@ public class AppOpsManager { sOpStrToOp.put(sOpToString[i], i); } } - for (int i=0; i<_NUM_OP; i++) { - if (sOpPerms[i] != null) { - sPermToOp.put(sOpPerms[i], i); + for (int op : RUNTIME_PERMISSIONS_OPS) { + if (sOpPerms[op] != null) { + sRuntimePermToOp.put(sOpPerms[op], op); } } } @@ -1016,10 +1053,12 @@ public class AppOpsManager { /** * Retrieve the app op code for a permission, or null if there is not one. + * This API is intended to be used for mapping runtime permissions to the + * corresponding app op. * @hide */ public static int permissionToOpCode(String permission) { - Integer boxedOpCode = sPermToOp.get(permission); + Integer boxedOpCode = sRuntimePermToOp.get(permission); return boxedOpCode != null ? boxedOpCode : OP_NONE; } @@ -1352,12 +1391,14 @@ public class AppOpsManager { * Gets the app op name associated with a given permission. * The app op name is one of the public constants defined * in this class such as {@link #OPSTR_COARSE_LOCATION}. + * This API is intended to be used for mapping runtime + * permissions to the corresponding app op. * * @param permission The permission. * @return The app op associated with the permission or null. */ public static String permissionToOp(String permission) { - final Integer opCode = sPermToOp.get(permission); + final Integer opCode = sRuntimePermToOp.get(permission); if (opCode == null) { return null; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 55ce6c2a9804..849fcec5a01a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -331,7 +331,7 @@ public interface IActivityManager extends IInterface { public void forceStopPackage(final String packageName, int userId) throws RemoteException; // Note: probably don't want to allow applications access to these. - public void setLockScreenShown(boolean shown) throws RemoteException; + public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException; public void unhandledBack() throws RemoteException; public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException; @@ -546,6 +546,8 @@ public interface IActivityManager extends IInterface { public void performIdleMaintenance() throws RemoteException; + public void sendIdleJobTrigger() throws RemoteException; + public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken, IActivityContainerCallback callback) throws RemoteException; @@ -1035,4 +1037,5 @@ public interface IActivityManager extends IInterface { int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372; int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373; int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374; + int SEND_IDLE_JOB_TRIGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 375; } diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 92a38171a160..17a802d59f4f 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -385,9 +385,13 @@ public final class ScanFilter implements Parcelable { @Override public int hashCode() { - return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, mManufacturerData, - mManufacturerDataMask, mServiceDataUuid, mServiceData, mServiceDataMask, - mServiceUuid, mServiceUuidMask); + return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, + Arrays.hashCode(mManufacturerData), + Arrays.hashCode(mManufacturerDataMask), + mServiceDataUuid, + Arrays.hashCode(mServiceData), + Arrays.hashCode(mServiceDataMask), + mServiceUuid, mServiceUuidMask); } @Override @@ -401,10 +405,10 @@ public final class ScanFilter implements Parcelable { ScanFilter other = (ScanFilter) obj; return Objects.equals(mDeviceName, other.mDeviceName) && Objects.equals(mDeviceAddress, other.mDeviceAddress) && - mManufacturerId == other.mManufacturerId && + mManufacturerId == other.mManufacturerId && Objects.deepEquals(mManufacturerData, other.mManufacturerData) && Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) && - Objects.deepEquals(mServiceDataUuid, other.mServiceDataUuid) && + Objects.equals(mServiceDataUuid, other.mServiceDataUuid) && Objects.deepEquals(mServiceData, other.mServiceData) && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) && Objects.equals(mServiceUuid, other.mServiceUuid) && diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl index 812f1fe5e563..6523192b735a 100644 --- a/core/java/android/net/INetworkPolicyListener.aidl +++ b/core/java/android/net/INetworkPolicyListener.aidl @@ -23,5 +23,6 @@ oneway interface INetworkPolicyListener { void onMeteredIfacesChanged(in String[] meteredIfaces); void onRestrictBackgroundChanged(boolean restrictBackground); void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted); + void onRestrictPowerChanged(boolean restrictPower); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 224ff5b395c7..fc9b8dd5f5bb 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -54,6 +54,7 @@ interface INetworkPolicyManager { /** Control if background data is restricted system-wide. */ void setRestrictBackground(boolean restrictBackground); boolean getRestrictBackground(); + boolean getRestrictPower(); /** Callback used to change internal state on tethering */ void onTetheringChanged(String iface, boolean tethering); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index e464a4a31497..51c45e056092 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -28,10 +28,10 @@ import android.content.pm.Signature; import android.os.RemoteException; import android.os.UserHandle; import android.text.format.Time; +import android.util.DebugUtils; import com.google.android.collect.Sets; -import java.io.PrintWriter; import java.util.HashSet; /** @@ -49,18 +49,39 @@ public class NetworkPolicyManager { /** Allow network use (metered or not) in the background in battery save mode. */ public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2; - /* RULE_* are not masks and they must be exclusive */ - public static final int RULE_UNKNOWN = -1; - /** All network traffic should be allowed. */ - public static final int RULE_ALLOW_ALL = 0; - /** Reject traffic on metered networks. */ - public static final int RULE_REJECT_METERED = 1; - /** Reject traffic on all networks. */ - public static final int RULE_REJECT_ALL = 2; + /* + * Rules defining whether an uid has access to a network given its type (metered / non-metered). + * + * These rules are bits and can be used in bitmask operations; in particular: + * - rule & RULE_MASK_METERED: returns the metered-networks status. + * - rule & RULE_MASK_ALL: returns the all-networks status. + * + * The RULE_xxx_ALL rules applies to all networks (metered or non-metered), but on + * metered networks, the RULE_xxx_METERED rules should be checked first. For example, + * if the device is on Battery Saver Mode and Data Saver Mode simulatenously, and a uid + * is whitelisted for the former but not the latter, its status would be + * RULE_REJECT_METERED | RULE_ALLOW_ALL, meaning it could have access to non-metered + * networks but not to metered networks. + * + * See network-policy-restrictions.md for more info. + */ + /** No specific rule was set */ + public static final int RULE_NONE = 0; /** Allow traffic on metered networks. */ - public static final int RULE_ALLOW_METERED = 3; + public static final int RULE_ALLOW_METERED = 1 << 0; /** Temporarily allow traffic on metered networks because app is on foreground. */ - public static final int RULE_TEMPORARY_ALLOW_METERED = 4; + public static final int RULE_TEMPORARY_ALLOW_METERED = 1 << 1; + /** Reject traffic on metered networks. */ + public static final int RULE_REJECT_METERED = 1 << 2; + /** Network traffic should be allowed on all networks (metered or non-metered), although + * metered-network restrictions could still apply. */ + public static final int RULE_ALLOW_ALL = 1 << 5; + /** Reject traffic on all networks. */ + public static final int RULE_REJECT_ALL = 1 << 6; + /** Mask used to get the {@code RULE_xxx_METERED} rules */ + public static final int MASK_METERED_NETWORKS = 0b00001111; + /** Mask used to get the {@code RULE_xxx_ALL} rules */ + public static final int MASK_ALL_NETWORKS = 0b11110000; public static final int FIREWALL_RULE_DEFAULT = 0; public static final int FIREWALL_RULE_ALLOW = 1; @@ -341,4 +362,18 @@ public class NetworkPolicyManager { // nothing found above; we can apply policy to UID return true; } + + /* + * @hide + */ + public static String uidRulesToString(int uidRules) { + final StringBuilder string = new StringBuilder().append(uidRules).append(" ("); + if (uidRules == RULE_NONE) { + string.append("NONE"); + } else { + string.append(DebugUtils.flagsToString(NetworkPolicyManager.class, "RULE_", uidRules)); + } + string.append(")"); + return string.toString(); + } } diff --git a/core/java/android/net/network-policy-restrictions.md b/core/java/android/net/network-policy-restrictions.md new file mode 100644 index 000000000000..fe13f7a5aab9 --- /dev/null +++ b/core/java/android/net/network-policy-restrictions.md @@ -0,0 +1,47 @@ +# Data Saver vs Battery Saver + +The tables below show whether an app has network access while on background depending on the status of Data Saver mode, Battery Saver mode, and the app's whitelist on those restricted modes. + +### How to read the tables + +The 2 topmost rows define the Battery Saver mode and whether the app is whitelisted or not for it. +The 2 leftmost columns define the Data Saver mode and whether the app is whitelisted, not whitelisted, or blacklisted for it. +The cells define the network status when the app is on background. + +More specifically: + +* **DS ON**: Data Saver Mode is on +* **DS OFF**: Data Saver Mode is off +* **BS ON**: Battery Saver Mode is on +* **BS OFF**: Battery Saver Mode is off +* **WL**: app is whitelisted +* **!WL**: app is not whitelisted +* **BL**: app is blacklisted +* **ok**: network access granted while app on background (NetworkInfo's state/detailed state should be `CONNECTED` / `CONNECTED`) +* **blk**: network access blocked while app on background (NetworkInfo's state/detailed state should be `DISCONNECTED` / `BLOCKED`) + + +## On metered networks + +| | | BS | ON | BS | OFF | +|:-------:|-------|------|-------|------|-------| +| | | *WL* | *!WL* | *WL* | *!WL* | +| **DS** | *WL* | ok | blk | ok | ok | +| **ON** | *!WL* | blk | blk | blk | blk | +| | *BL* | blk | blk | blk | blk | +| **DS** | *WL* | blk | ok | ok | ok | +| **OFF** | *!WL* | blk | ok | ok | ok | +| | *BL* | blk | blk | blk | blk | + + +## On non-metered networks + +| | | BS | ON | BS | OFF | +|:-------:|-------|------|-------|------|-------| +| | | *WL* | *!WL* | *WL* | *!WL* | +| **DS** | *WL* | ok | blk | ok | ok | +| **ON** | *!WL* | ok | blk | ok | ok | +| | *BL* | ok | blk | ok | ok | +| **DS** | *WL* | ok | blk | ok | ok | +| **OFF** | *!WL* | ok | blk | ok | ok | +| | *BL* | ok | blk | ok | ok | diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 8c8d38f18875..02ee2df18aaf 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -658,6 +658,13 @@ public class RadialTimePickerView extends View { if (animate) { animatePicker(hours, ANIM_DURATION_NORMAL); + } else { + // If we have a pending or running animator, cancel it. + if (mHoursToMinutesAnimator != null && mHoursToMinutesAnimator.isStarted()) { + mHoursToMinutesAnimator.cancel(); + mHoursToMinutesAnimator = null; + } + mHoursToMinutes = hours ? 0.0f : 1.0f; } initData(); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9725e4f94160..e68d8a68e7c2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -307,7 +307,7 @@ <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" /> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" /> - <protected-broadcast android:name="com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE" /> + <protected-broadcast android:name="com.android.server.ACTION_TRIGGER_IDLE" /> <protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" /> diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java new file mode 100644 index 000000000000..fc9c9d335467 --- /dev/null +++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java @@ -0,0 +1,107 @@ +/* + * 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 android.net; + +import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; +import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS; +import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; +import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; +import static android.net.NetworkPolicyManager.RULE_NONE; +import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; +import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; +import static android.net.NetworkPolicyManager.uidRulesToString; + +import junit.framework.TestCase; + +public class NetworkPolicyManagerTest extends TestCase { + + public void testUidRulesToString() { + uidRulesToStringTest(RULE_NONE, "0 (NONE)"); + uidRulesToStringTest(RULE_ALLOW_METERED, "1 (ALLOW_METERED)"); + uidRulesToStringTest(RULE_TEMPORARY_ALLOW_METERED, "2 (TEMPORARY_ALLOW_METERED)"); + uidRulesToStringTest(RULE_REJECT_METERED, "4 (REJECT_METERED)"); + uidRulesToStringTest(RULE_ALLOW_ALL, "32 (ALLOW_ALL)"); + uidRulesToStringTest(RULE_REJECT_ALL, "64 (REJECT_ALL)"); + + uidRulesToStringTest(RULE_ALLOW_METERED | RULE_ALLOW_ALL, + "33 (ALLOW_METERED|ALLOW_ALL)"); + uidRulesToStringTest(RULE_ALLOW_METERED | RULE_REJECT_ALL, + "65 (ALLOW_METERED|REJECT_ALL)"); + uidRulesToStringTest(RULE_TEMPORARY_ALLOW_METERED | RULE_ALLOW_ALL, + "34 (TEMPORARY_ALLOW_METERED|ALLOW_ALL)"); + uidRulesToStringTest(RULE_TEMPORARY_ALLOW_METERED | RULE_REJECT_ALL, + "66 (TEMPORARY_ALLOW_METERED|REJECT_ALL)"); + uidRulesToStringTest(RULE_REJECT_METERED | RULE_ALLOW_ALL, + "36 (REJECT_METERED|ALLOW_ALL)"); + uidRulesToStringTest(RULE_REJECT_METERED | RULE_REJECT_ALL, + "68 (REJECT_METERED|REJECT_ALL)"); + } + + private void uidRulesToStringTest(int uidRules, String expected) { + final String actual = uidRulesToString(uidRules); + assertEquals("Wrong string for uidRules " + uidRules, expected, actual); + } + + public void testMeteredNetworksMask() { + assertEquals(RULE_NONE, MASK_METERED_NETWORKS + & RULE_NONE); + + assertEquals(RULE_ALLOW_METERED, MASK_METERED_NETWORKS + & RULE_ALLOW_METERED); + assertEquals(RULE_ALLOW_METERED, MASK_METERED_NETWORKS + & (RULE_ALLOW_METERED | RULE_ALLOW_ALL)); + assertEquals(RULE_ALLOW_METERED, MASK_METERED_NETWORKS + & (RULE_ALLOW_METERED | RULE_REJECT_ALL)); + + assertEquals(RULE_TEMPORARY_ALLOW_METERED, MASK_METERED_NETWORKS + & RULE_TEMPORARY_ALLOW_METERED); + assertEquals(RULE_TEMPORARY_ALLOW_METERED, MASK_METERED_NETWORKS + & (RULE_TEMPORARY_ALLOW_METERED | RULE_ALLOW_ALL)); + assertEquals(RULE_TEMPORARY_ALLOW_METERED, MASK_METERED_NETWORKS + & (RULE_TEMPORARY_ALLOW_METERED | RULE_REJECT_ALL)); + + assertEquals(RULE_REJECT_METERED, MASK_METERED_NETWORKS + & RULE_REJECT_METERED); + assertEquals(RULE_REJECT_METERED, MASK_METERED_NETWORKS + & (RULE_REJECT_METERED | RULE_ALLOW_ALL)); + assertEquals(RULE_REJECT_METERED, MASK_METERED_NETWORKS + & (RULE_REJECT_METERED | RULE_REJECT_ALL)); + } + + public void testAllNetworksMask() { + assertEquals(RULE_NONE, MASK_ALL_NETWORKS + & RULE_NONE); + + assertEquals(RULE_ALLOW_ALL, MASK_ALL_NETWORKS + & RULE_ALLOW_ALL); + assertEquals(RULE_ALLOW_ALL, MASK_ALL_NETWORKS + & (RULE_ALLOW_ALL | RULE_ALLOW_METERED)); + assertEquals(RULE_ALLOW_ALL, MASK_ALL_NETWORKS + & (RULE_ALLOW_ALL | RULE_TEMPORARY_ALLOW_METERED)); + assertEquals(RULE_ALLOW_ALL, MASK_ALL_NETWORKS + & (RULE_ALLOW_ALL | RULE_REJECT_METERED)); + + assertEquals(RULE_REJECT_ALL, MASK_ALL_NETWORKS + & RULE_REJECT_ALL); + assertEquals(RULE_REJECT_ALL, MASK_ALL_NETWORKS + & (RULE_REJECT_ALL | RULE_ALLOW_METERED)); + assertEquals(RULE_REJECT_ALL, MASK_ALL_NETWORKS + & (RULE_REJECT_ALL | RULE_TEMPORARY_ALLOW_METERED)); + assertEquals(RULE_REJECT_ALL, MASK_ALL_NETWORKS + & (RULE_REJECT_ALL | RULE_REJECT_METERED)); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index 2db8fad714a9..5e7a229fda9d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -170,6 +170,7 @@ public class DirectoryFragment extends Fragment private RootInfo mRoot; private DocumentInfo mDocument; private String mQuery = null; + // Save selection found during creation so it can be restored during directory loading. private Selection mSelection = null; private boolean mSearchMode = false; private @Nullable ActionMode mActionMode; @@ -698,7 +699,7 @@ public class DirectoryFragment extends Fragment public final boolean onBackPressed() { if (mSelectionManager.hasSelection()) { - if (DEBUG) Log.d(TAG, "Clearing selection on back pressed."); + if (DEBUG) Log.d(TAG, "Clearing selection on selection manager."); mSelectionManager.clearSelection(); return true; } @@ -1817,6 +1818,7 @@ public class DirectoryFragment extends Fragment if (mSelection != null) { mSelectionManager.setItemsSelected(mSelection.toList(), true); + mSelection.clear(); } // Restore any previous instance state diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 86119426a3e7..5d629401dff3 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -141,17 +141,13 @@ android:gravity="top" systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" /> - <com.android.systemui.statusbar.AlphaOptimizedButton + <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/alarm_status_collapsed" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:drawablePadding="6dp" - android:drawableStart="@drawable/ic_access_alarms_small" - android:textColor="#64ffffff" - android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" + android:layout_height="match_parent" + android:src="@drawable/ic_access_alarms_small" android:paddingStart="6dp" - android:gravity="top" - android:background="?android:attr/selectableItemBackground" + android:gravity="center" android:visibility="gone" /> </LinearLayout> @@ -171,7 +167,6 @@ <com.android.systemui.qs.QuickQSPanel android:id="@+id/quick_qs_panel" - android:background="#0000" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="28dp" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 55fa10bc238d..cad7f647e031 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1542,7 +1542,7 @@ public class KeyguardViewMediator extends SystemUI { private void updateActivityLockScreenState() { try { - ActivityManagerNative.getDefault().setLockScreenShown(mShowing && !mOccluded); + ActivityManagerNative.getDefault().setLockScreenShown(mShowing, mOccluded); } catch (RemoteException e) { } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index afb2195d9f99..a5f3e7700cf8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -41,6 +41,7 @@ import android.view.WindowManager.LayoutParams; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; @@ -69,7 +70,6 @@ import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent; import com.android.systemui.recents.events.ui.StackViewScrolledEvent; import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent; import com.android.systemui.recents.events.ui.UserInteractionEvent; -import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; @@ -89,7 +89,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; /** - * The main Recents activity that is started from AlternateRecentsComponent. + * The main Recents activity that is started from RecentsComponent. */ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { @@ -166,6 +166,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD if (action.equals(Intent.ACTION_SCREEN_OFF)) { // When the screen turns off, dismiss Recents to Home dismissRecentsToHomeIfVisible(false); + } else if (action.equals(Intent.ACTION_TIME_CHANGED)) { + // For the time being, if the time changes, then invalidate the + // last-stack-active-time, this ensures that we will just show the last N tasks + // the next time that Recents loads, but prevents really old tasks from showing + // up if the task time is set forward. + Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, + 0); } } }; @@ -311,6 +318,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // Register the broadcast receiver to handle messages when the screen is turned off IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_TIME_CHANGED); registerReceiver(mSystemBroadcastReceiver, filter); getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION); @@ -751,13 +759,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD mIgnoreAltTabRelease = true; } - public final void onBusEvent(final DragEndEvent event) { - // Handle the case where we drop onto a dock region - if (event.dropTarget instanceof TaskStack.DockState) { - mScrimViews.animateScrimToCurrentNavBarState(false /* hasStackTasks */); - } - } - public final void onBusEvent(final DockedTopTaskEvent event) { mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener); mRecentsView.invalidate(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java new file mode 100644 index 000000000000..edd799597ea6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java @@ -0,0 +1,39 @@ +/* + * 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.events.ui.dragndrop; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.recents.views.DropTarget; +import com.android.systemui.recents.views.TaskView; + +/** + * This event is sent whenever a drag end is cancelled because of an error. + */ +public class DragEndCancelledEvent extends EventBus.AnimatedEvent { + + public final TaskStack stack; + public final Task task; + public final TaskView taskView; + + public DragEndCancelledEvent(TaskStack stack, Task task, TaskView taskView) { + this.stack = stack; + this.task = task; + this.taskView = taskView; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 46b2612ee7f0..08b52d94ad20 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -393,18 +393,19 @@ public class SystemServicesProxy { } /** Docks a task to the side of the screen and starts it. */ - public void startTaskInDockedMode(int taskId, int createMode) { - if (mIam == null) return; + public boolean startTaskInDockedMode(int taskId, int createMode) { + if (mIam == null) return false; try { - // TODO: Determine what animation we want for the incoming task final ActivityOptions options = ActivityOptions.makeBasic(); options.setDockCreateMode(createMode); options.setLaunchStackId(DOCKED_STACK_ID); mIam.startActivityFromRecents(taskId, options.toBundle()); - } catch (RemoteException e) { + return true; + } catch (RemoteException | IllegalArgumentException e) { e.printStackTrace(); } + return false; } /** Docks an already resumed task to the side of the screen. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index f6cc12bebb12..9fb8bd557b90 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -226,6 +226,18 @@ public class Utilities { } /** + * Sets the given {@link View}'s frame from its current translation. + */ + public static void setViewFrameFromTranslation(View v) { + RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); + taskViewRect.offset(v.getTranslationX(), v.getTranslationY()); + v.setTranslationX(0); + v.setTranslationY(0); + v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top, + (int) taskViewRect.right, (int) taskViewRect.bottom); + } + + /** * Returns a view stub for the given view id. */ public static ViewStub findViewStubById(View v, int stubId) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 397909580b0d..251ad71e5d62 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -140,39 +140,10 @@ public class RecentsTaskLoadPlan { lastStackActiveTime = 0; } long newLastStackActiveTime = -1; - long prevLastActiveTime = lastStackActiveTime; int taskCount = mRawTasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = mRawTasks.get(i); - /* - * Affiliated tasks are returned in a specific order from ActivityManager but without a - * lastActiveTime since it hasn't yet been started. However, we later sort the task list - * by lastActiveTime, which rearranges the tasks. For now, we need to workaround this - * by updating the lastActiveTime of this task to the lastActiveTime of the task it is - * affiliated with, in the same order that we encounter it in the original list (just - * its index in the task group for the task it is affiliated with). - * - * If the parent task is not available, then we will use the last active time of the - * previous task as a base point (since the task itself may not have an active time) - * for the entire affiliated group. - */ - if (t.persistentId != t.affiliatedTaskId) { - Task.TaskKey parentTask = affiliatedTasks.get(t.affiliatedTaskId); - long parentTaskLastActiveTime = parentTask != null - ? parentTask.lastActiveTime - : prevLastActiveTime; - if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) { - t.lastActiveTime = parentTaskLastActiveTime + - affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1; - } else { - if (t.lastActiveTime == 0) { - t.lastActiveTime = parentTaskLastActiveTime - - affiliatedTaskCounts.get(t.affiliatedTaskId, 0) - 1; - } - } - } - // Compose the task key Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent, t.userId, t.firstActiveTime, t.lastActiveTime); @@ -180,9 +151,14 @@ public class RecentsTaskLoadPlan { // This task is only shown in the stack if it statisfies the historical time or min // number of tasks constraints. Freeform tasks are also always shown. boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId); - boolean isStackTask = isFreeformTask || (!isHistoricalTask(t) || - (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS))); + boolean isStackTask = isFreeformTask || !isHistoricalTask(t) || + (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)); boolean isLaunchTarget = taskKey.id == runningTaskId; + + // The last stack active time is the baseline for which we show visible tasks. Since + // the system will store all the tasks, we don't want to show the tasks prior to the + // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy + // the other stack-task constraints. if (isStackTask && newLastStackActiveTime < 0) { newLastStackActiveTime = t.lastActiveTime; } @@ -211,7 +187,6 @@ public class RecentsTaskLoadPlan { allTasks.add(task); affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1); affiliatedTasks.put(taskKey.id, taskKey); - prevLastActiveTime = t.lastActiveTime; } if (newLastStackActiveTime != -1) { Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index c6528a157d7a..86a0315496a1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -118,6 +118,11 @@ public class Task { public TaskKey key; /** + * The temporary sort index in the stack, used when ordering the stack. + */ + public int temporarySortIndexInStack; + + /** * The group will be computed separately from the initialization of the task */ @ViewDebug.ExportedProperty(deepExport=true, prefix="group_") diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java index c63a494963a9..23739a083826 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java @@ -76,7 +76,8 @@ public class TaskKeyLruCache<V> { final V getAndInvalidateIfModified(Task.TaskKey key) { Task.TaskKey lastKey = mKeys.get(key.id); if (lastKey != null) { - if ((lastKey.stackId != key.stackId) || (lastKey.lastActiveTime < key.lastActiveTime)) { + if ((lastKey.stackId != key.stackId) || + (lastKey.lastActiveTime != key.lastActiveTime)) { // The task has updated (been made active since the last time it was put into the // LRU cache) or the stack id for the task has changed, invalidate that cache item remove(key); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index f42eea335e6f..50e28ca2205d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -517,16 +517,8 @@ public class TaskStack { } } - // A comparator that sorts tasks by their last active time - private Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() { - @Override - public int compare(Task o1, Task o2) { - return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime); - } - }; - - // A comparator that sorts tasks by their last active time and freeform state - private Comparator<Task> FREEFORM_LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() { + // A comparator that sorts tasks by their freeform state + private Comparator<Task> FREEFORM_COMPARATOR = new Comparator<Task>() { @Override public int compare(Task o1, Task o2) { if (o1.isFreeformTask() && !o2.isFreeformTask()) { @@ -534,7 +526,7 @@ public class TaskStack { } else if (o2.isFreeformTask() && !o1.isFreeformTask()) { return -1; } - return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime); + return Long.compare(o1.temporarySortIndexInStack, o2.temporarySortIndexInStack); } }; @@ -696,7 +688,10 @@ public class TaskStack { } // Sort all the tasks to ensure they are ordered correctly - Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR); + for (int i = allTasks.size() - 1; i >= 0; i--) { + allTasks.get(i).temporarySortIndexInStack = i; + } + Collections.sort(allTasks, FREEFORM_COMPARATOR); mStackTaskList.set(allTasks); mRawTaskList = allTasks; @@ -769,12 +764,11 @@ public class TaskStack { } /** - * Computes a set of all the active and historical tasks ordered by their last active time. + * Computes a set of all the active and historical tasks. */ public ArrayList<Task> computeAllTasksList() { ArrayList<Task> tasks = new ArrayList<>(); tasks.addAll(mStackTaskList.getTasks()); - Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR); return tasks; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java index 9dc9c4c19e5d..acebf427feab 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java @@ -350,13 +350,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { } else { mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); } - if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) { - // If there are 2 or more tasks, and we are not launching from home - // set the selected position to the 2nd task to allow for faster app switching - mTaskStackHorizontalGridView.setSelectedPosition(1); - } else { - mTaskStackHorizontalGridView.setSelectedPosition(0); - } // If this is a new instance from a configuration change, then we have to manually trigger // the enter animation state, or if recents was relaunched by AM, without going through @@ -382,6 +375,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { if(mLaunchedFromHome) { mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown()); } + mTaskStackViewAdapter.setResetAddedCards(true); EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent()); } @@ -389,12 +383,20 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { public void onResume() { super.onResume(); mPipRecentsOverlayManager.onRecentsResumed(); + if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) { + // If there are 2 or more tasks, and we are not launching from home + // set the selected position to the 2nd task to allow for faster app switching + mTaskStackHorizontalGridView.setSelectedPosition(1); + } else { + mTaskStackHorizontalGridView.setSelectedPosition(0); + } } @Override public void onPause() { super.onPause(); mPipRecentsOverlayManager.onRecentsPaused(); + mTaskStackViewAdapter.setResetAddedCards(false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java index 084fc874b7b9..65f5fffc5acc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java @@ -18,7 +18,6 @@ package com.android.systemui.recents.tv.animations; import android.animation.Animator.AnimatorListener; import android.content.res.Resources; import android.graphics.drawable.TransitionDrawable; -import android.util.TypedValue; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; @@ -39,7 +38,7 @@ public class DismissAnimationsHolder { private TransitionDrawable mDismissDrawable; private TextView mDismissText; - private float mDismissUnselectedAlpha; + private float mDismissIconNotInDismissStateAlpha; private long mShortDuration; private long mLongDuration; @@ -57,7 +56,7 @@ public class DismissAnimationsHolder { mDismissStartYDelta = mDismissEnterYDelta * 2; mShortDuration = res.getInteger(R.integer.dismiss_short_duration); mLongDuration = res.getInteger(R.integer.dismiss_long_duration); - mDismissUnselectedAlpha = res.getFloat(R.integer.dismiss_unselected_alpha); + mDismissIconNotInDismissStateAlpha = res.getFloat(R.integer.dismiss_unselected_alpha); } public void startEnterAnimation() { @@ -94,7 +93,7 @@ public class DismissAnimationsHolder { mCardDismissIcon.animate() .setDuration(mShortDuration) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .alpha(mDismissUnselectedAlpha) + .alpha(mDismissIconNotInDismissStateAlpha) .withEndAction(new Runnable() { @Override public void run() { @@ -157,7 +156,7 @@ public class DismissAnimationsHolder { mInfoField.animate().setListener(null); mThumbnailView.setAlpha(1.0f); mThumbnailView.setTranslationY(0); - mCardDismissIcon.setAlpha(mDismissUnselectedAlpha); + mCardDismissIcon.setAlpha(0.0f); mDismissText.setAlpha(0.0f); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java index eb3b02d155eb..ed28ef173f0f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java @@ -42,6 +42,7 @@ public class TaskStackHorizontalViewAdapter extends private static final String TAG = "TaskStackViewAdapter"; private List<Task> mTaskList; private TaskStackHorizontalGridView mGridView; + private boolean mResetAddedCards; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private TaskCardView mTaskCardView; @@ -126,6 +127,13 @@ public class TaskStackHorizontalViewAdapter extends } @Override + public void onViewAttachedToWindow(ViewHolder holder) { + if (mResetAddedCards) { + holder.mTaskCardView.reset(); + } + } + + @Override public void onViewDetachedFromWindow(ViewHolder holder) { // We only want to reset on view detach if this is the last task being dismissed. // This is so that we do not reset when shifting to apps etc, as it is not needed. @@ -171,4 +179,8 @@ public class TaskStackHorizontalViewAdapter extends mTaskList.add(position, task); notifyItemInserted(position); } + + public void setResetAddedCards(boolean reset) { + mResetAddedCards = reset; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index fd27b4f1fc27..a8939100f66d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -64,6 +64,7 @@ import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; import com.android.systemui.recents.events.ui.DraggingInRecentsEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; +import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; @@ -510,45 +511,43 @@ public class RecentsView extends FrameLayout { // We translated the view but we need to animate it back from the current layout-space // rect to its final layout-space rect - int x = (int) event.taskView.getTranslationX(); - int y = (int) event.taskView.getTranslationY(); - Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(), - event.taskView.getRight(), event.taskView.getBottom()); - taskViewRect.offset(x, y); - event.taskView.setTranslationX(0); - event.taskView.setTranslationY(0); - event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top, - taskViewRect.right, taskViewRect.bottom); - - final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() { - @Override - public void onAnimationStarted() { - EventBus.getDefault().send(new DockedFirstAnimationFrameEvent()); - // Remove the task and don't bother relaying out, as all the tasks will be - // relaid out when the stack changes on the multiwindow change event - mTaskStackView.getStack().removeTask(event.task, null, - true /* fromDockGesture */); - } - }; + Utilities.setViewFrameFromTranslation(event.taskView); // Dock the task and launch it SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode); - final Rect taskRect = getTaskRect(event.taskView); - IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture( - new AnimationSpecComposer() { - @Override - public List<AppTransitionAnimationSpec> composeSpecs() { - return mTransitionHelper.composeDockAnimationSpec( - event.taskView, taskRect); - } - }); - ssp.overridePendingAppTransitionMultiThumbFuture(future, - mTransitionHelper.wrapStartedListener(startedListener), - true /* scaleUp */); - - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, - event.task.getTopComponent().flattenToShortString()); + if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) { + final OnAnimationStartedListener startedListener = + new OnAnimationStartedListener() { + @Override + public void onAnimationStarted() { + EventBus.getDefault().send(new DockedFirstAnimationFrameEvent()); + // Remove the task and don't bother relaying out, as all the tasks will be + // relaid out when the stack changes on the multiwindow change event + mTaskStackView.getStack().removeTask(event.task, null, + true /* fromDockGesture */); + } + }; + + final Rect taskRect = getTaskRect(event.taskView); + IAppTransitionAnimationSpecsFuture future = + mTransitionHelper.getAppTransitionFuture( + new AnimationSpecComposer() { + @Override + public List<AppTransitionAnimationSpec> composeSpecs() { + return mTransitionHelper.composeDockAnimationSpec( + event.taskView, taskRect); + } + }); + ssp.overridePendingAppTransitionMultiThumbFuture(future, + mTransitionHelper.wrapStartedListener(startedListener), + true /* scaleUp */); + + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, + event.task.getTopComponent().flattenToShortString()); + } else { + EventBus.getDefault().send(new DragEndCancelledEvent(mStack, event.task, + event.taskView)); + } } else { // Animate the overlay alpha back to 0 updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1, @@ -565,6 +564,12 @@ public class RecentsView extends FrameLayout { } } + public final void onBusEvent(final DragEndCancelledEvent event) { + // Animate the overlay alpha back to 0 + updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1, + true /* animateAlpha */, false /* animateBounds */); + } + private Rect getTaskRect(TaskView taskView) { int[] location = taskView.getLocationOnScreen(); int viewX = location[0]; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index 995f9f74a2f0..8f784b832e4c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -28,6 +28,9 @@ import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimatio import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent; +import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent; +import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; +import com.android.systemui.recents.model.TaskStack; /** Manages the scrims for the various system bars. */ public class SystemBarScrimViews { @@ -154,10 +157,22 @@ public class SystemBarScrimViews { animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0); } + public final void onBusEvent(final DragEndEvent event) { + // Hide the nav bar scrims once we drop to a dock region + if (event.dropTarget instanceof TaskStack.DockState) { + animateScrimToCurrentNavBarState(false /* hasStackTasks */); + } + } + + public final void onBusEvent(final DragEndCancelledEvent event) { + // Restore the scrims to the normal state + animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0); + } + /** * Animates the scrim to match the state of the current nav bar. */ - public void animateScrimToCurrentNavBarState(boolean hasStackTasks) { + private void animateScrimToCurrentNavBarState(boolean hasStackTasks) { boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks); if (mHasNavBarScrim != hasNavBarScrim) { AnimationProps animation = hasNavBarScrim diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 773e5875b04f..3d0de1cab1e9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -79,6 +79,7 @@ import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEv import com.android.systemui.recents.events.ui.UserInteractionEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; +import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent; import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; @@ -640,19 +641,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** - * @see #relayoutTaskViews(AnimationProps, boolean) + * @see #relayoutTaskViews(AnimationProps, ArrayMap<Task, AnimationProps>, boolean) */ public void relayoutTaskViews(AnimationProps animation) { - relayoutTaskViews(animation, false /* ignoreTaskOverrides */); + relayoutTaskViews(animation, null /* animationOverrides */, + false /* ignoreTaskOverrides */); } /** * Relayout the the visible {@link TaskView}s to their current transforms as specified by the * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any * animations that are current running on those task views, and will ensure that the children - * {@link TaskView}s will match the set of visible tasks in the stack. + * {@link TaskView}s will match the set of visible tasks in the stack. If a {@link Task} has + * an animation provided in {@param animationOverrides}, that will be used instead. */ - private void relayoutTaskViews(AnimationProps animation, boolean ignoreTaskOverrides) { + private void relayoutTaskViews(AnimationProps animation, + ArrayMap<Task, AnimationProps> animationOverrides, + boolean ignoreTaskOverrides) { // If we had a deferred animation, cancel that cancelDeferredTaskViewLayoutAnimation(); @@ -665,13 +670,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int taskViewCount = taskViews.size(); for (int i = 0; i < taskViewCount; i++) { TaskView tv = taskViews.get(i); - int taskIndex = mStack.indexOfStackTask(tv.getTask()); + Task task = tv.getTask(); + int taskIndex = mStack.indexOfStackTask(task); TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex); - if (mIgnoreTasks.contains(tv.getTask().key)) { + if (mIgnoreTasks.contains(task.key)) { continue; } + if (animationOverrides != null && animationOverrides.containsKey(task)) { + animation = animationOverrides.get(task); + } + updateTaskViewToTransform(tv, transform, animation); } } @@ -829,6 +839,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + /** + * Updates the stack layout to its stable places. + */ + private void updateLayoutToStableBounds() { + mWindowRect.set(mStableWindowRect); + mStackBounds.set(mStableStackBounds); + mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets); + mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds, + TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); + updateLayoutAlgorithm(true /* boundScroll */); + } + /** Returns the scroller. */ public TaskStackViewScroller getScroller() { return mStackScroller; @@ -1820,16 +1842,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } else { // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging // task view, so add it back to the ignore set after updating the layout - mWindowRect.set(mStableWindowRect); - mStackBounds.set(mStableStackBounds); removeIgnoreTask(event.task); - mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets); - mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds, - TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); - updateLayoutAlgorithm(true /* boundScroll */); + updateLayoutToStableBounds(); addIgnoreTask(event.task); } - relayoutTaskViews(animation, ignoreTaskOverrides); + relayoutTaskViews(animation, null /* animationOverrides */, ignoreTaskOverrides); } public final void onBusEvent(final DragEndEvent event) { @@ -1867,30 +1884,38 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal }); } - // We translated the view but we need to animate it back from the current layout-space rect - // to its final layout-space rect - int x = (int) event.taskView.getTranslationX(); - int y = (int) event.taskView.getTranslationY(); - Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(), - event.taskView.getRight(), event.taskView.getBottom()); - taskViewRect.offset(x, y); - event.taskView.setTranslationX(0); - event.taskView.setTranslationY(0); - event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top, - taskViewRect.right, taskViewRect.bottom); + // Restore the task, so that relayout will apply to it below + removeIgnoreTask(event.task); - // Animate the non-drag TaskViews back into position - mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(), - mTmpTransform, null); - event.getAnimationTrigger().increment(); - relayoutTaskViews(new AnimationProps(DEFAULT_SYNC_STACK_DURATION, + // Convert the dragging task view back to its final layout-space rect + Utilities.setViewFrameFromTranslation(event.taskView); + + // Animate all the tasks into place + ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>(); + animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION, + Interpolators.FAST_OUT_SLOW_IN, + event.getAnimationTrigger().decrementOnAnimationEnd())); + relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN)); + event.getAnimationTrigger().increment(); + } - // Animate the drag TaskView back into position - updateTaskViewToTransform(event.taskView, mTmpTransform, - new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN, - event.getAnimationTrigger().decrementOnAnimationEnd())); + public final void onBusEvent(final DragEndCancelledEvent event) { + // Restore the pre-drag task stack bounds, including the dragging task view removeIgnoreTask(event.task); + updateLayoutToStableBounds(); + + // Convert the dragging task view back to its final layout-space rect + Utilities.setViewFrameFromTranslation(event.taskView); + + // Animate all the tasks into place + ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>(); + animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION, + Interpolators.FAST_OUT_SLOW_IN, + event.getAnimationTrigger().decrementOnAnimationEnd())); + relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION, + Interpolators.FAST_OUT_SLOW_IN)); + event.getAnimationTrigger().increment(); } public final void onBusEvent(IterateRecentsEvent event) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index c1e7e0403c88..612c41d07a04 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -49,6 +49,7 @@ import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.LaunchTaskEvent; import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; +import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; @@ -695,15 +696,18 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks public final void onBusEvent(DragEndEvent event) { if (!(event.dropTarget instanceof TaskStack.DockState)) { - event.addPostAnimationCallback(new Runnable() { - @Override - public void run() { - // Animate the drag view back from where it is, to the view location, then after - // it returns, update the clip state - setClipViewInStack(true); - } + event.addPostAnimationCallback(() -> { + // Reset the clip state for the drag view after the end animation completes + setClipViewInStack(true); }); } EventBus.getDefault().unregister(this); } + + public final void onBusEvent(DragEndCancelledEvent event) { + // Reset the clip state for the drag view after the cancel animation completes + event.addPostAnimationCallback(() -> { + setClipViewInStack(true); + }); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java index ec45d604b829..ee4a10293760 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -282,6 +282,12 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId()); if (indexOfKey >= 0) { mButtonDispatchers.valueAt(indexOfKey).addView(v); + } else if (v instanceof ViewGroup) { + final ViewGroup viewGroup = (ViewGroup)v; + final int N = viewGroup.getChildCount(); + for (int i = 0; i < N; i++) { + addToDispatchers(viewGroup.getChildAt(i)); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index e32d51a234af..d6deba06d4da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -57,7 +57,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements protected View mSettingsContainer; private TextView mAlarmStatus; - private TextView mAlarmStatusCollapsed; + private View mAlarmStatusCollapsed; private QSPanel mQsPanel; @@ -117,7 +117,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mSettingsContainer = findViewById(R.id.settings_button_container); mSettingsButton.setOnClickListener(this); - mAlarmStatusCollapsed = (TextView) findViewById(R.id.alarm_status_collapsed); + mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed); mAlarmStatus = (TextView) findViewById(R.id.alarm_status); mAlarmStatus.setOnClickListener(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java index e6e189f0ffd8..0bca241c8842 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java @@ -91,6 +91,10 @@ public class DataSaverController { } @Override + public void onRestrictPowerChanged(boolean restrictPower) { + } + + @Override public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) { } }; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 06255a29f98b..8763b93f31b9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -30,10 +30,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; -import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; +import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS; +import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; +import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; -import static android.net.NetworkPolicyManager.RULE_UNKNOWN; +import static android.net.NetworkPolicyManager.uidRulesToString; import android.annotation.Nullable; import android.app.BroadcastOptions; @@ -216,6 +218,9 @@ public class ConnectivityService extends IConnectivityManager.Stub /** Flag indicating if background data is restricted. */ @GuardedBy("mRulesLock") private boolean mRestrictBackground; + /** Flag indicating if background data is restricted due to battery savings. */ + @GuardedBy("mRulesLock") + private boolean mRestrictPower; final private Context mContext; private int mNetworkPreference; @@ -664,9 +669,10 @@ public class ConnectivityService extends IConnectivityManager.Stub try { mPolicyManager.setConnectivityListener(mPolicyListener); mRestrictBackground = mPolicyManager.getRestrictBackground(); + mRestrictPower = mPolicyManager.getRestrictPower(); } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network - loge("unable to register INetworkPolicyListener" + e.toString()); + loge("unable to register INetworkPolicyListener" + e); } final PowerManager powerManager = (PowerManager) context.getSystemService( @@ -915,24 +921,36 @@ public class ConnectivityService extends IConnectivityManager.Stub final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { networkMetered = mMeteredIfaces.contains(iface); - uidRules = mUidRules.get(uid, RULE_UNKNOWN); + uidRules = mUidRules.get(uid, RULE_NONE); } - switch (uidRules) { - case RULE_ALLOW_ALL: - case RULE_ALLOW_METERED: - case RULE_TEMPORARY_ALLOW_METERED: - return false; - case RULE_REJECT_METERED: - return networkMetered; - case RULE_REJECT_ALL: - return true; - case RULE_UNKNOWN: - default: - // When background data is restricted device-wide, the default - // behavior for apps should be like RULE_REJECT_METERED - return mRestrictBackground ? networkMetered : false; + boolean allowed = true; + // Check Data Saver Mode first... + if (networkMetered) { + if ((uidRules & RULE_REJECT_METERED) != 0) { + if (LOGD_RULES) Log.d(TAG, "uid " + uid + " is blacklisted"); + // Explicitly blacklisted. + allowed = false; + } else { + allowed = !mRestrictBackground + || (uidRules & RULE_ALLOW_METERED) != 0 + || (uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0; + if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + + " mRestrictBackground=" + mRestrictBackground + + ", whitelisted=" + ((uidRules & RULE_ALLOW_METERED) != 0) + + ", tempWhitelist= + ((uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0)" + + ": " + allowed); + } + } + // ...then Battery Saver Mode. + if (allowed && mRestrictPower) { + allowed = (uidRules & RULE_ALLOW_ALL) != 0; + if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + + " mRestrictPower=" + mRestrictPower + + ", whitelisted=" + ((uidRules & RULE_ALLOW_ALL) != 0) + + ": " + allowed); } + return !allowed; } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { @@ -1379,7 +1397,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mRulesLock) { // skip update when we've already applied rules - final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL); + final int oldRules = mUidRules.get(uid, RULE_NONE); if (oldRules == uidRules) return; mUidRules.put(uid, uidRules); @@ -1421,6 +1439,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override + public void onRestrictPowerChanged(boolean restrictPower) { + // caller is NPMS, since we only register with them + if (LOGD_RULES) { + log("onRestrictPowerChanged(restrictPower=" + restrictPower + ")"); + } + + synchronized (mRulesLock) { + mRestrictPower = restrictPower; + } + } + + @Override public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) { if (LOGD_RULES) { // caller is NPMS, since we only register with them @@ -1861,6 +1891,25 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println(mRestrictBackground); pw.println(); + pw.print("Restrict power: "); + pw.println(mRestrictPower); + pw.println(); + + pw.println("Status for known UIDs:"); + pw.increaseIndent(); + final int size = mUidRules.size(); + for (int i = 0; i < size; i++) { + final int uid = mUidRules.keyAt(i); + pw.print("UID="); + pw.print(uid); + final int uidRules = mUidRules.get(uid, RULE_NONE); + pw.print(" rules="); + pw.print(uidRulesToString(uidRules)); + pw.println(); + } + pw.println(); + pw.decreaseIndent(); + pw.println("Network Requests:"); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -3982,9 +4031,9 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized(mRulesLock) { uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); } - if (uidRules != RULE_ALLOW_ALL) { + if ((uidRules & RULE_ALLOW_ALL) == 0) { // we could silently fail or we can filter the available nets to only give - // them those they have access to. Chose the more useful + // them those they have access to. Chose the more useful option. networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 2418160255f8..e5b301e803af 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -330,6 +330,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (DBG) Slog.d(TAG, "Awaiting socket connection"); connectedSignal.await(); if (DBG) Slog.d(TAG, "Connected"); + service.connectNativeNetdService(); return service; } @@ -560,11 +561,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } - /** - * Prepare native daemon once connected, enabling modules and pushing any - * existing in-memory rules. - */ - private void prepareNativeDaemon() { + private void connectNativeNetdService() { boolean nativeServiceAvailable = false; try { mNetdService = INetd.Stub.asInterface(ServiceManager.getService(NETD_SERVICE_NAME)); @@ -573,6 +570,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (!nativeServiceAvailable) { Slog.wtf(TAG, "Can't connect to NativeNetdService " + NETD_SERVICE_NAME); } + } + + /** + * Prepare native daemon once connected, enabling modules and pushing any + * existing in-memory rules. + */ + private void prepareNativeDaemon() { mBandwidthControlEnabled = false; @@ -767,12 +771,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub // event is dispatched from internal NDC thread, so we prepare the // daemon back on main thread. if (mConnectedSignal != null) { + // The system is booting and we're connecting to netd for the first time. mConnectedSignal.countDown(); mConnectedSignal = null; } else { + // We're reconnecting to netd after the socket connection + // was interrupted (e.g., if it crashed). mFgHandler.post(new Runnable() { @Override public void run() { + connectNativeNetdService(); prepareNativeDaemon(); } }); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 94118e62b495..f52bda978ab0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -390,6 +390,11 @@ public final class ActivityManagerService extends ActivityManagerNative private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND; + // Mock "pretend we're idle now" broadcast action to the job scheduler; declared + // here so that while the job scheduler can depend on AMS, the other way around + // need not be the case. + public static final String ACTION_TRIGGER_IDLE = "com.android.server.ACTION_TRIGGER_IDLE"; + /** Control over CPU and battery monitoring */ // write battery stats every 30 minutes. static final long BATTERY_STATS_TIME = 30 * 60 * 1000; @@ -11476,7 +11481,7 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setEventDispatching(mBooted && !mShuttingDown); } - public void setLockScreenShown(boolean shown) { + public void setLockScreenShown(boolean showing, boolean occluded) { if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " @@ -11486,8 +11491,17 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(this) { long ident = Binder.clearCallingIdentity(); try { - if (DEBUG_LOCKSCREEN) logLockScreen(" shown=" + shown); - mLockScreenShown = shown ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN; + if (DEBUG_LOCKSCREEN) logLockScreen(" showing=" + showing + " occluded=" + occluded); + mLockScreenShown = (showing && !occluded) ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN; + if (showing && occluded) { + // The lock screen is currently showing, but is occluded by a window that can + // show on top of the lock screen. In this can we want to dismiss the docked + // stack since it will be complicated/risky to try to put the activity on top + // of the lock screen in the right fullscreen configuration. + mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID, + mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID); + } + updateSleepIfNeededLocked(); } finally { Binder.restoreCallingIdentity(ident); @@ -12649,6 +12663,26 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public void sendIdleJobTrigger() { + if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.SET_ACTIVITY_WATCHER); + } + + final long ident = Binder.clearCallingIdentity(); + try { + Intent intent = new Intent(ACTION_TRIGGER_IDLE) + .setPackage("android") + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + broadcastIntent(null, intent, null, null, 0, null, null, null, + android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void retrieveSettings() { final ContentResolver resolver = mContext.getContentResolver(); final boolean freeformWindowManagement = diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index dac710d759bd..d74e22e57e55 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1008,13 +1008,14 @@ final class ActivityStack { void goToSleep() { ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - // Make sure any stopped but visible activities are now sleeping. + // Make sure any paused or stopped but visible activities are now sleeping. // This ensures that the activity's onStop() is called. for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); - if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) { + if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED + || r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) { r.setSleeping(true); } } diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index 88faee73322f..cea76f236fc9 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -65,6 +65,9 @@ class RecentTasks extends ArrayList<TaskRecord> { private static final int MAX_RECENT_BITMAPS = 3; private static final int DEFAULT_INITIAL_CAPACITY = 5; + // Whether or not to move all affiliated tasks to the front when one of the tasks is launched + private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false; + /** * Save recent tasks information across reboots. */ @@ -513,7 +516,7 @@ class RecentTasks extends ArrayList<TaskRecord> { if (task.inRecents) { int taskIndex = indexOf(task); if (taskIndex >= 0) { - if (!isAffiliated) { + if (!isAffiliated || MOVE_AFFILIATED_TASKS_TO_FRONT) { // Simple case: this is not an affiliated task, so we just move it to the front. remove(taskIndex); add(0, task); diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 9fd22686a9a0..e0179dcc9586 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -170,6 +170,11 @@ public class ConnectivityController extends StateController implements } @Override + public void onRestrictPowerChanged(boolean restrictPower) { + updateTrackedJobs(-1); + } + + @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { updateTrackedJobs(-1); } diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java index c7a679cc4697..5899d1647ad8 100644 --- a/services/core/java/com/android/server/job/controllers/IdleController.java +++ b/services/core/java/com/android/server/job/controllers/IdleController.java @@ -28,15 +28,13 @@ import android.content.IntentFilter; import android.os.SystemClock; import android.util.Slog; +import com.android.server.am.ActivityManagerService; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateChangedListener; public class IdleController extends StateController { private static final String TAG = "IdleController"; - private static final String ACTION_TRIGGER_IDLE = - "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"; - // Policy: we decide that we're "idle" if the device has been unused / // screen off or dreaming for at least this long private long mInactivityIdleThreshold; @@ -113,7 +111,7 @@ public class IdleController extends StateController { public IdlenessTracker() { mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(ACTION_TRIGGER_IDLE) + Intent intent = new Intent(ActivityManagerService.ACTION_TRIGGER_IDLE) .setPackage("android") .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); @@ -140,7 +138,7 @@ public class IdleController extends StateController { filter.addAction(Intent.ACTION_DREAMING_STOPPED); // Debugging/instrumentation - filter.addAction(ACTION_TRIGGER_IDLE); + filter.addAction(ActivityManagerService.ACTION_TRIGGER_IDLE); mContext.registerReceiver(this, filter); } @@ -176,7 +174,7 @@ public class IdleController extends StateController { mScreenOn = false; mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mIdleWindowSlop, mIdleTriggerIntent); - } else if (action.equals(ACTION_TRIGGER_IDLE)) { + } else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) { // idle time starts now. Do not set mIdle if screen is on. if (!mIdle && !mScreenOn) { if (DEBUG) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index a6055c1716f7..344ba179e4c7 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -48,11 +48,16 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; +import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; +import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS; +import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; +import static android.net.NetworkPolicyManager.RULE_NONE; +import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; -import static android.net.NetworkPolicyManager.RULE_UNKNOWN; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; +import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; import static android.net.NetworkTemplate.MATCH_MOBILE_4G; import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; @@ -261,6 +266,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED = 9; private static final int MSG_UPDATE_INTERFACE_QUOTA = 10; private static final int MSG_REMOVE_INTERFACE_QUOTA = 11; + private static final int MSG_RESTRICT_POWER_CHANGED = 12; private final Context mContext; private final IActivityManager mActivityManager; @@ -551,9 +557,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRulesForGlobalChangeLocked(true); } } + mHandler.obtainMessage(MSG_RESTRICT_POWER_CHANGED, + enabled ? 1 : 0, 0).sendToTarget(); } }); + final boolean oldRestrictPower = mRestrictPower; mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled(); + if (mRestrictPower != oldRestrictPower) { + // Some early services may have read the default value, + // so notify them that it's changed + mHandler.obtainMessage(MSG_RESTRICT_POWER_CHANGED, + mRestrictPower ? 1 : 0, 0).sendToTarget(); + } + mSystemReady = true; // read policy from disk @@ -2048,13 +2064,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted, boolean updateNow) { final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid); - if (!oldStatus) { + if (!oldStatus && !uidDeleted) { if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before"); return false; } final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid); - Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist"); - mRestrictBackgroundWhitelistUids.delete(uid); + if (oldStatus) { + Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist"); + mRestrictBackgroundWhitelistUids.delete(uid); + } if (mDefaultRestrictBackgroundWhitelistUids.get(uid) && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) { if (LOGD) Slog.d(TAG, "Adding uid " + uid @@ -2128,6 +2146,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override + public boolean getRestrictPower() { + mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + + synchronized (mRulesLock) { + return mRestrictPower; + } + } + + @Override public void setDeviceIdleMode(boolean enabled) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); @@ -2352,7 +2379,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { collectKeys(mUidState, knownUids); collectKeys(mUidRules, knownUids); - fout.println("Status for known UIDs:"); + fout.println("Status for all known UIDs:"); fout.increaseIndent(); size = knownUids.size(); for (int i = 0; i < size; i++) { @@ -2370,20 +2397,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { ? " (fg svc)" : " (bg)"); } - final int rule = mUidRules.get(uid, RULE_UNKNOWN); - fout.print(" rule="); - fout.print(ruleToString(rule)); + final int uidRules = mUidRules.get(uid, RULE_NONE); + fout.print(" rules="); + fout.print(uidRulesToString(uidRules)); + fout.println(); + } + fout.decreaseIndent(); + fout.println("Status for just UIDs with rules:"); + fout.increaseIndent(); + size = mUidRules.size(); + for (int i = 0; i < size; i++) { + final int uid = mUidRules.keyAt(i); + fout.print("UID="); + fout.print(uid); + final int uidRules = mUidRules.get(uid, RULE_NONE); + fout.print(" rules="); + fout.print(uidRulesToString(uidRules)); fout.println(); } fout.decreaseIndent(); } } - private String ruleToString(int rule) { - return DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule); - } - @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver) throws RemoteException { @@ -2564,12 +2600,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { enableFirewallChainLocked(chain, enabled); } + private boolean isWhitelistedBatterySaverLocked(int uid) { + final int appId = UserHandle.getAppId(uid); + return mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId); + } + // NOTE: since both fw_dozable and fw_powersave uses the same map // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method. private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) { if (enabled) { - int appId = UserHandle.getAppId(uid); - if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId) + if (isWhitelistedBatterySaverLocked(uid) || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) { setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW); } else { @@ -2732,7 +2772,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * <p>There are currently 2 types of restriction rules: * <ul> * <li>Battery Saver Mode (also referred as power save). - * <li>Data Saver Mode (formerly known as restrict background data). + * <li>Data Saver Mode (The Feature Formerly Known As 'Restrict Background Data'). * </ul> */ private void updateRestrictionRulesForUidLocked(int uid) { @@ -2777,6 +2817,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * have permission to use the internet. * * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID. + * + * <p>This method also updates the {@link #mUidRules} with the power-related status for the uid + * and send the proper {@value #MSG_RULES_CHANGED} notification, although it does not change + * the power-related firewall rules per se. */ private void updateRuleForRestrictBackgroundLocked(int uid) { updateRuleForRestrictBackgroundLocked(uid, false); @@ -2793,42 +2837,70 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); + final int oldUidRules = mUidRules.get(uid, RULE_NONE); final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid); - final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; - final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid); - int newRule = RULE_UNKNOWN; - final int oldRule = mUidRules.get(uid, RULE_UNKNOWN); + // Data Saver status. + final boolean isDsBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; + final boolean isDsWhitelisted = mRestrictBackgroundWhitelistUids.get(uid); + final int oldDsRule = oldUidRules & MASK_METERED_NETWORKS; + int newDsRule = RULE_NONE; + + // Battery Saver status. + final boolean isBsWhitelisted = isWhitelistedBatterySaverLocked(uid); + final int oldBsRule = oldUidRules & MASK_ALL_NETWORKS; + int newBsRule = RULE_NONE; // First step: define the new rule based on user restrictions and foreground state. if (isForeground) { - if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) { - newRule = RULE_TEMPORARY_ALLOW_METERED; + // Data Saver rules + if (isDsBlacklisted || (mRestrictBackground && !isDsWhitelisted)) { + newDsRule = RULE_TEMPORARY_ALLOW_METERED; + } else if (isDsWhitelisted) { + newDsRule = RULE_ALLOW_METERED; + } + // Battery Saver rules + if (mRestrictPower) { + newBsRule = RULE_ALLOW_ALL; } } else { - if (isBlacklisted) { - newRule = RULE_REJECT_METERED; - } else if (isWhitelisted) { - newRule = RULE_ALLOW_METERED; + // Data Saver rules + if (isDsBlacklisted) { + newDsRule = RULE_REJECT_METERED; + } else if (mRestrictBackground && isDsWhitelisted) { + newDsRule = RULE_ALLOW_METERED; + } + // Battery Saver rules + if (mRestrictPower) { + newBsRule = isBsWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL; } } + final int newUidRules = newDsRule | newBsRule; if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + "):" - + " isForeground=" +isForeground + ", isBlacklisted: " + isBlacklisted - + ", isWhitelisted: " + isWhitelisted + ", newRule: " + ruleToString(newRule) - + ", oldRule: " + ruleToString(oldRule)); + + " isForeground=" +isForeground + ", isBlacklisted: " + isDsBlacklisted + + ", isDsWhitelisted: " + isDsWhitelisted + + ", isBsWhitelisted: " + isBsWhitelisted + + ", newUidRules: " + uidRulesToString(newUidRules) + + ", oldUidRules: " + uidRulesToString(oldUidRules)); } - if (newRule == RULE_UNKNOWN) { + if (newUidRules == RULE_NONE) { mUidRules.delete(uid); } else { - mUidRules.put(uid, newRule); + mUidRules.put(uid, newUidRules); } + boolean changed = false; + // Second step: apply bw changes based on change of state. - if (newRule != oldRule) { - if (newRule == RULE_TEMPORARY_ALLOW_METERED) { + + // Apply Data Saver rules. + if (newDsRule != oldDsRule) { + changed = true; + + if ((newDsRule & RULE_TEMPORARY_ALLOW_METERED) != 0) { // Temporarily whitelist foreground app, removing from blacklist if necessary // (since bw_penalty_box prevails over bw_happy_box). @@ -2836,44 +2908,69 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // TODO: if statement below is used to avoid an unnecessary call to netd / iptables, // but ideally it should be just: // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (isBlacklisted) { + if (isDsBlacklisted) { setMeteredNetworkBlacklist(uid, false); } - } else if (oldRule == RULE_TEMPORARY_ALLOW_METERED) { + } else if ((oldDsRule & RULE_TEMPORARY_ALLOW_METERED) != 0) { // Remove temporary whitelist from app that is not on foreground anymore. // TODO: if statements below are used to avoid unnecessary calls to netd / iptables, // but ideally they should be just: // setMeteredNetworkWhitelist(uid, isWhitelisted); // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (!isWhitelisted) { + if (!isDsWhitelisted) { setMeteredNetworkWhitelist(uid, false); } - if (isBlacklisted) { + if (isDsBlacklisted) { setMeteredNetworkBlacklist(uid, true); } - } else if (newRule == RULE_REJECT_METERED || oldRule == RULE_REJECT_METERED) { + } else if ((newDsRule & RULE_REJECT_METERED) != 0 + || (oldDsRule & RULE_REJECT_METERED) != 0) { // Flip state because app was explicitly added or removed to blacklist. - setMeteredNetworkBlacklist(uid, isBlacklisted); - if (oldRule == RULE_REJECT_METERED && isWhitelisted) { + setMeteredNetworkBlacklist(uid, isDsBlacklisted); + if ((oldDsRule & RULE_REJECT_METERED) != 0 && isDsWhitelisted) { // Since blacklist prevails over whitelist, we need to handle the special case // where app is whitelisted and blacklisted at the same time (although such // scenario should be blocked by the UI), then blacklist is removed. - setMeteredNetworkWhitelist(uid, isWhitelisted); + setMeteredNetworkWhitelist(uid, isDsWhitelisted); } - } else if (newRule == RULE_ALLOW_METERED || oldRule == RULE_ALLOW_METERED) { + } else if ((newDsRule & RULE_ALLOW_METERED) != 0 + || (oldDsRule & RULE_ALLOW_METERED) != 0) { // Flip state because app was explicitly added or removed to whitelist. - setMeteredNetworkWhitelist(uid, isWhitelisted); + setMeteredNetworkWhitelist(uid, isDsWhitelisted); } else { // All scenarios should have been covered above - Log.wtf(TAG, "Unexpected change of state for " + uid - + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted - + ", blacklisted=" + isBlacklisted + ", newRule=" - + ruleToString(newRule) + ", oldRule=" + ruleToString(oldRule)); + Log.wtf(TAG, "Unexpected change of metered UID state for " + uid + + ": foreground=" + isForeground + + ", whitelisted=" + isDsWhitelisted + + ", blacklisted=" + isDsBlacklisted + + ", newRule=" + uidRulesToString(newUidRules) + + ", oldRule=" + uidRulesToString(oldUidRules)); } + } - // dispatch changed rule to existing listeners - mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget(); + // Apply Battery Saver rules. + // NOTE: the firewall rules are changed outside this method, but it's still necessary to + // send the MSG_RULES_CHANGED so ConnectivityService can update its internal status. + if (newBsRule != oldBsRule) { + changed = true; + if (newBsRule == RULE_NONE || (newBsRule & RULE_ALLOW_ALL) != 0) { + if (LOGV) Log.v(TAG, "Allowing non-metered access for UID " + uid); + } else if ((newBsRule & RULE_REJECT_ALL) != 0) { + if (LOGV) Log.v(TAG, "Rejecting non-metered access for UID " + uid); + } else { + // All scenarios should have been covered above + Log.wtf(TAG, "Unexpected change of non-metered UID state for " + uid + + ": foreground=" + isForeground + + ", whitelisted=" + isBsWhitelisted + + ", newRule=" + uidRulesToString(newUidRules) + + ", oldRule=" + uidRulesToString(oldUidRules)); + } + } + + // Final step: dispatch changed rule to existing listeners + if (changed) { + mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget(); } } @@ -2939,6 +3036,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void dispatchRestrictPowerChanged(INetworkPolicyListener listener, + boolean restrictPower) { + if (listener != null) { + try { + listener.onRestrictPowerChanged(restrictPower); + } catch (RemoteException ignored) { + } + } + } + private Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { @@ -2986,6 +3093,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return true; } + case MSG_RESTRICT_POWER_CHANGED: { + final boolean restrictPower = msg.arg1 != 0; + dispatchRestrictPowerChanged(mConnectivityListener, restrictPower); + return true; + } case MSG_RESTRICT_BACKGROUND_CHANGED: { final boolean restrictBackground = msg.arg1 != 0; dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground); diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 381449c16213..ca68d55dfb83 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -378,6 +378,9 @@ public class DockedStackDividerController implements DimLayerUser { } private void checkMinimizeChanged(boolean animate) { + if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) { + return; + } final TaskStack homeStack = mDisplayContent.getHomeStack(); if (homeStack == null) { return; @@ -412,8 +415,7 @@ public class DockedStackDividerController implements DimLayerUser { private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) { final boolean wasMinimized = mMinimizedDock; mMinimizedDock = minimizedDock; - if (minimizedDock == wasMinimized - || mDisplayContent.getDockedStackVisibleForUserLocked() == null) { + if (minimizedDock == wasMinimized) { return; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e73d547a7b87..7341e1ea1b8c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1995,12 +1995,17 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mAppToken.shouldSaveSurface(); } + static final Region sEmptyRegion = new Region(); + void destroyOrSaveSurface() { mSurfaceSaved = shouldSaveSurface(); if (mSurfaceSaved) { if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { Slog.v(TAG, "Saving surface: " + this); } + // Previous user of the surface may have set a transparent region signaling a portion + // doesn't need to be composited, so reset to default empty state. + mSession.setTransparentRegion(mClient, sEmptyRegion); mWinAnimator.hide("saved surface"); mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE; |