Merge "Fix thread priority after boosting." into nyc-mr1-dev
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3f8bad1..f994d7e 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -67,10 +67,4 @@
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage);
-
- /**
- * Called by AM when the system locale changes *within the AM lock*. ABSOLUTELY do not take
- * any locks in this method.
- */
- public abstract void onSystemLocaleChangedNoLock();
}
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
index b62cc66..b6d720d 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -32,111 +32,112 @@
0x23EC, 0x23ED, 0x23EE, 0x23EF, 0x23F0, 0x23F1, 0x23F2, 0x23F3, 0x23F8, 0x23F9, 0x23FA,
0x24C2, 0x25AA, 0x25AB, 0x25B6, 0x25C0, 0x25FB, 0x25FC, 0x25FD, 0x25FE, 0x2600, 0x2601,
0x2602, 0x2603, 0x2604, 0x260E, 0x2611, 0x2614, 0x2615, 0x2618, 0x261D, 0x2620, 0x2622,
- 0x2623, 0x2626, 0x262A, 0x262E, 0x262F, 0x2638, 0x2639, 0x263A, 0x2648, 0x2649, 0x264A,
- 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653, 0x2660, 0x2663,
- 0x2665, 0x2666, 0x2668, 0x267B, 0x267F, 0x2692, 0x2693, 0x2694, 0x2696, 0x2697, 0x2699,
- 0x269B, 0x269C, 0x26A0, 0x26A1, 0x26AA, 0x26AB, 0x26B0, 0x26B1, 0x26BD, 0x26BE, 0x26C4,
- 0x26C5, 0x26C8, 0x26CE, 0x26CF, 0x26D1, 0x26D3, 0x26D4, 0x26E9, 0x26EA, 0x26F0, 0x26F1,
- 0x26F2, 0x26F3, 0x26F4, 0x26F5, 0x26F7, 0x26F8, 0x26F9, 0x26FA, 0x26FD, 0x2702, 0x2705,
- 0x2708, 0x2709, 0x270A, 0x270B, 0x270C, 0x270D, 0x270F, 0x2712, 0x2714, 0x2716, 0x271D,
- 0x2721, 0x2728, 0x2733, 0x2734, 0x2744, 0x2747, 0x274C, 0x274E, 0x2753, 0x2754, 0x2755,
- 0x2757, 0x2763, 0x2764, 0x2795, 0x2796, 0x2797, 0x27A1, 0x27B0, 0x27BF, 0x2934, 0x2935,
- 0x2B05, 0x2B06, 0x2B07, 0x2B1B, 0x2B1C, 0x2B50, 0x2B55, 0x3030, 0x303D, 0x3297, 0x3299,
- 0x1F004, 0x1F0CF, 0x1F170, 0x1F171, 0x1F17E, 0x1F17F, 0x1F18E, 0x1F191, 0x1F192, 0x1F193,
- 0x1F194, 0x1F195, 0x1F196, 0x1F197, 0x1F198, 0x1F199, 0x1F19A, 0x1F1E6, 0x1F1E7, 0x1F1E8,
- 0x1F1E9, 0x1F1EA, 0x1F1EB, 0x1F1EC, 0x1F1ED, 0x1F1EE, 0x1F1EF, 0x1F1F0, 0x1F1F1, 0x1F1F2,
- 0x1F1F3, 0x1F1F4, 0x1F1F5, 0x1F1F6, 0x1F1F7, 0x1F1F8, 0x1F1F9, 0x1F1FA, 0x1F1FB, 0x1F1FC,
- 0x1F1FD, 0x1F1FE, 0x1F1FF, 0x1F201, 0x1F202, 0x1F21A, 0x1F22F, 0x1F232, 0x1F233, 0x1F234,
- 0x1F235, 0x1F236, 0x1F237, 0x1F238, 0x1F239, 0x1F23A, 0x1F250, 0x1F251, 0x1F300, 0x1F301,
- 0x1F302, 0x1F303, 0x1F304, 0x1F305, 0x1F306, 0x1F307, 0x1F308, 0x1F309, 0x1F30A, 0x1F30B,
- 0x1F30C, 0x1F30D, 0x1F30E, 0x1F30F, 0x1F310, 0x1F311, 0x1F312, 0x1F313, 0x1F314, 0x1F315,
- 0x1F316, 0x1F317, 0x1F318, 0x1F319, 0x1F31A, 0x1F31B, 0x1F31C, 0x1F31D, 0x1F31E, 0x1F31F,
- 0x1F320, 0x1F321, 0x1F324, 0x1F325, 0x1F326, 0x1F327, 0x1F328, 0x1F329, 0x1F32A, 0x1F32B,
- 0x1F32C, 0x1F32D, 0x1F32E, 0x1F32F, 0x1F330, 0x1F331, 0x1F332, 0x1F333, 0x1F334, 0x1F335,
- 0x1F336, 0x1F337, 0x1F338, 0x1F339, 0x1F33A, 0x1F33B, 0x1F33C, 0x1F33D, 0x1F33E, 0x1F33F,
- 0x1F340, 0x1F341, 0x1F342, 0x1F343, 0x1F344, 0x1F345, 0x1F346, 0x1F347, 0x1F348, 0x1F349,
- 0x1F34A, 0x1F34B, 0x1F34C, 0x1F34D, 0x1F34E, 0x1F34F, 0x1F350, 0x1F351, 0x1F352, 0x1F353,
- 0x1F354, 0x1F355, 0x1F356, 0x1F357, 0x1F358, 0x1F359, 0x1F35A, 0x1F35B, 0x1F35C, 0x1F35D,
- 0x1F35E, 0x1F35F, 0x1F360, 0x1F361, 0x1F362, 0x1F363, 0x1F364, 0x1F365, 0x1F366, 0x1F367,
- 0x1F368, 0x1F369, 0x1F36A, 0x1F36B, 0x1F36C, 0x1F36D, 0x1F36E, 0x1F36F, 0x1F370, 0x1F371,
- 0x1F372, 0x1F373, 0x1F374, 0x1F375, 0x1F376, 0x1F377, 0x1F378, 0x1F379, 0x1F37A, 0x1F37B,
- 0x1F37C, 0x1F37D, 0x1F37E, 0x1F37F, 0x1F380, 0x1F381, 0x1F382, 0x1F383, 0x1F384, 0x1F385,
- 0x1F386, 0x1F387, 0x1F388, 0x1F389, 0x1F38A, 0x1F38B, 0x1F38C, 0x1F38D, 0x1F38E, 0x1F38F,
- 0x1F390, 0x1F391, 0x1F392, 0x1F393, 0x1F396, 0x1F397, 0x1F399, 0x1F39A, 0x1F39B, 0x1F39E,
- 0x1F39F, 0x1F3A0, 0x1F3A1, 0x1F3A2, 0x1F3A3, 0x1F3A4, 0x1F3A5, 0x1F3A6, 0x1F3A7, 0x1F3A8,
- 0x1F3A9, 0x1F3AA, 0x1F3AB, 0x1F3AC, 0x1F3AD, 0x1F3AE, 0x1F3AF, 0x1F3B0, 0x1F3B1, 0x1F3B2,
- 0x1F3B3, 0x1F3B4, 0x1F3B5, 0x1F3B6, 0x1F3B7, 0x1F3B8, 0x1F3B9, 0x1F3BA, 0x1F3BB, 0x1F3BC,
- 0x1F3BD, 0x1F3BE, 0x1F3BF, 0x1F3C0, 0x1F3C1, 0x1F3C2, 0x1F3C3, 0x1F3C4, 0x1F3C5, 0x1F3C6,
- 0x1F3C7, 0x1F3C8, 0x1F3C9, 0x1F3CA, 0x1F3CB, 0x1F3CC, 0x1F3CD, 0x1F3CE, 0x1F3CF, 0x1F3D0,
- 0x1F3D1, 0x1F3D2, 0x1F3D3, 0x1F3D4, 0x1F3D5, 0x1F3D6, 0x1F3D7, 0x1F3D8, 0x1F3D9, 0x1F3DA,
- 0x1F3DB, 0x1F3DC, 0x1F3DD, 0x1F3DE, 0x1F3DF, 0x1F3E0, 0x1F3E1, 0x1F3E2, 0x1F3E3, 0x1F3E4,
- 0x1F3E5, 0x1F3E6, 0x1F3E7, 0x1F3E8, 0x1F3E9, 0x1F3EA, 0x1F3EB, 0x1F3EC, 0x1F3ED, 0x1F3EE,
- 0x1F3EF, 0x1F3F0, 0x1F3F3, 0x1F3F4, 0x1F3F5, 0x1F3F7, 0x1F3F8, 0x1F3F9, 0x1F3FA, 0x1F3FB,
- 0x1F3FC, 0x1F3FD, 0x1F3FE, 0x1F3FF, 0x1F400, 0x1F401, 0x1F402, 0x1F403, 0x1F404, 0x1F405,
- 0x1F406, 0x1F407, 0x1F408, 0x1F409, 0x1F40A, 0x1F40B, 0x1F40C, 0x1F40D, 0x1F40E, 0x1F40F,
- 0x1F410, 0x1F411, 0x1F412, 0x1F413, 0x1F414, 0x1F415, 0x1F416, 0x1F417, 0x1F418, 0x1F419,
- 0x1F41A, 0x1F41B, 0x1F41C, 0x1F41D, 0x1F41E, 0x1F41F, 0x1F420, 0x1F421, 0x1F422, 0x1F423,
- 0x1F424, 0x1F425, 0x1F426, 0x1F427, 0x1F428, 0x1F429, 0x1F42A, 0x1F42B, 0x1F42C, 0x1F42D,
- 0x1F42E, 0x1F42F, 0x1F430, 0x1F431, 0x1F432, 0x1F433, 0x1F434, 0x1F435, 0x1F436, 0x1F437,
- 0x1F438, 0x1F439, 0x1F43A, 0x1F43B, 0x1F43C, 0x1F43D, 0x1F43E, 0x1F43F, 0x1F440, 0x1F441,
- 0x1F442, 0x1F443, 0x1F444, 0x1F445, 0x1F446, 0x1F447, 0x1F448, 0x1F449, 0x1F44A, 0x1F44B,
- 0x1F44C, 0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F451, 0x1F452, 0x1F453, 0x1F454, 0x1F455,
- 0x1F456, 0x1F457, 0x1F458, 0x1F459, 0x1F45A, 0x1F45B, 0x1F45C, 0x1F45D, 0x1F45E, 0x1F45F,
- 0x1F460, 0x1F461, 0x1F462, 0x1F463, 0x1F464, 0x1F465, 0x1F466, 0x1F467, 0x1F468, 0x1F469,
- 0x1F46A, 0x1F46B, 0x1F46C, 0x1F46D, 0x1F46E, 0x1F46F, 0x1F470, 0x1F471, 0x1F472, 0x1F473,
- 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F479, 0x1F47A, 0x1F47B, 0x1F47C, 0x1F47D,
- 0x1F47E, 0x1F47F, 0x1F480, 0x1F481, 0x1F482, 0x1F483, 0x1F484, 0x1F485, 0x1F486, 0x1F487,
- 0x1F488, 0x1F489, 0x1F48A, 0x1F48B, 0x1F48C, 0x1F48D, 0x1F48E, 0x1F48F, 0x1F490, 0x1F491,
- 0x1F492, 0x1F493, 0x1F494, 0x1F495, 0x1F496, 0x1F497, 0x1F498, 0x1F499, 0x1F49A, 0x1F49B,
- 0x1F49C, 0x1F49D, 0x1F49E, 0x1F49F, 0x1F4A0, 0x1F4A1, 0x1F4A2, 0x1F4A3, 0x1F4A4, 0x1F4A5,
- 0x1F4A6, 0x1F4A7, 0x1F4A8, 0x1F4A9, 0x1F4AA, 0x1F4AB, 0x1F4AC, 0x1F4AD, 0x1F4AE, 0x1F4AF,
- 0x1F4B0, 0x1F4B1, 0x1F4B2, 0x1F4B3, 0x1F4B4, 0x1F4B5, 0x1F4B6, 0x1F4B7, 0x1F4B8, 0x1F4B9,
- 0x1F4BA, 0x1F4BB, 0x1F4BC, 0x1F4BD, 0x1F4BE, 0x1F4BF, 0x1F4C0, 0x1F4C1, 0x1F4C2, 0x1F4C3,
- 0x1F4C4, 0x1F4C5, 0x1F4C6, 0x1F4C7, 0x1F4C8, 0x1F4C9, 0x1F4CA, 0x1F4CB, 0x1F4CC, 0x1F4CD,
- 0x1F4CE, 0x1F4CF, 0x1F4D0, 0x1F4D1, 0x1F4D2, 0x1F4D3, 0x1F4D4, 0x1F4D5, 0x1F4D6, 0x1F4D7,
- 0x1F4D8, 0x1F4D9, 0x1F4DA, 0x1F4DB, 0x1F4DC, 0x1F4DD, 0x1F4DE, 0x1F4DF, 0x1F4E0, 0x1F4E1,
- 0x1F4E2, 0x1F4E3, 0x1F4E4, 0x1F4E5, 0x1F4E6, 0x1F4E7, 0x1F4E8, 0x1F4E9, 0x1F4EA, 0x1F4EB,
- 0x1F4EC, 0x1F4ED, 0x1F4EE, 0x1F4EF, 0x1F4F0, 0x1F4F1, 0x1F4F2, 0x1F4F3, 0x1F4F4, 0x1F4F5,
- 0x1F4F6, 0x1F4F7, 0x1F4F8, 0x1F4F9, 0x1F4FA, 0x1F4FB, 0x1F4FC, 0x1F4FD, 0x1F4FF, 0x1F500,
- 0x1F501, 0x1F502, 0x1F503, 0x1F504, 0x1F505, 0x1F506, 0x1F507, 0x1F508, 0x1F509, 0x1F50A,
- 0x1F50B, 0x1F50C, 0x1F50D, 0x1F50E, 0x1F50F, 0x1F510, 0x1F511, 0x1F512, 0x1F513, 0x1F514,
- 0x1F515, 0x1F516, 0x1F517, 0x1F518, 0x1F519, 0x1F51A, 0x1F51B, 0x1F51C, 0x1F51D, 0x1F51E,
- 0x1F51F, 0x1F520, 0x1F521, 0x1F522, 0x1F523, 0x1F524, 0x1F525, 0x1F526, 0x1F527, 0x1F528,
- 0x1F529, 0x1F52A, 0x1F52B, 0x1F52C, 0x1F52D, 0x1F52E, 0x1F52F, 0x1F530, 0x1F531, 0x1F532,
- 0x1F533, 0x1F534, 0x1F535, 0x1F536, 0x1F537, 0x1F538, 0x1F539, 0x1F53A, 0x1F53B, 0x1F53C,
- 0x1F53D, 0x1F549, 0x1F54A, 0x1F54B, 0x1F54C, 0x1F54D, 0x1F54E, 0x1F550, 0x1F551, 0x1F552,
- 0x1F553, 0x1F554, 0x1F555, 0x1F556, 0x1F557, 0x1F558, 0x1F559, 0x1F55A, 0x1F55B, 0x1F55C,
- 0x1F55D, 0x1F55E, 0x1F55F, 0x1F560, 0x1F561, 0x1F562, 0x1F563, 0x1F564, 0x1F565, 0x1F566,
- 0x1F567, 0x1F56F, 0x1F570, 0x1F573, 0x1F574, 0x1F575, 0x1F576, 0x1F577, 0x1F578, 0x1F579,
- 0x1F57A, 0x1F587, 0x1F58A, 0x1F58B, 0x1F58C, 0x1F58D, 0x1F590, 0x1F595, 0x1F596, 0x1F5A4,
- 0x1F5A5, 0x1F5A8, 0x1F5B1, 0x1F5B2, 0x1F5BC, 0x1F5C2, 0x1F5C3, 0x1F5C4, 0x1F5D1, 0x1F5D2,
- 0x1F5D3, 0x1F5DC, 0x1F5DD, 0x1F5DE, 0x1F5E1, 0x1F5E3, 0x1F5E8, 0x1F5EF, 0x1F5F3, 0x1F5FA,
- 0x1F5FB, 0x1F5FC, 0x1F5FD, 0x1F5FE, 0x1F5FF, 0x1F600, 0x1F601, 0x1F602, 0x1F603, 0x1F604,
- 0x1F605, 0x1F606, 0x1F607, 0x1F608, 0x1F609, 0x1F60A, 0x1F60B, 0x1F60C, 0x1F60D, 0x1F60E,
- 0x1F60F, 0x1F610, 0x1F611, 0x1F612, 0x1F613, 0x1F614, 0x1F615, 0x1F616, 0x1F617, 0x1F618,
- 0x1F619, 0x1F61A, 0x1F61B, 0x1F61C, 0x1F61D, 0x1F61E, 0x1F61F, 0x1F620, 0x1F621, 0x1F622,
- 0x1F623, 0x1F624, 0x1F625, 0x1F626, 0x1F627, 0x1F628, 0x1F629, 0x1F62A, 0x1F62B, 0x1F62C,
- 0x1F62D, 0x1F62E, 0x1F62F, 0x1F630, 0x1F631, 0x1F632, 0x1F633, 0x1F634, 0x1F635, 0x1F636,
- 0x1F637, 0x1F638, 0x1F639, 0x1F63A, 0x1F63B, 0x1F63C, 0x1F63D, 0x1F63E, 0x1F63F, 0x1F640,
- 0x1F641, 0x1F642, 0x1F643, 0x1F644, 0x1F645, 0x1F646, 0x1F647, 0x1F648, 0x1F649, 0x1F64A,
- 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F680, 0x1F681, 0x1F682, 0x1F683, 0x1F684,
- 0x1F685, 0x1F686, 0x1F687, 0x1F688, 0x1F689, 0x1F68A, 0x1F68B, 0x1F68C, 0x1F68D, 0x1F68E,
- 0x1F68F, 0x1F690, 0x1F691, 0x1F692, 0x1F693, 0x1F694, 0x1F695, 0x1F696, 0x1F697, 0x1F698,
- 0x1F699, 0x1F69A, 0x1F69B, 0x1F69C, 0x1F69D, 0x1F69E, 0x1F69F, 0x1F6A0, 0x1F6A1, 0x1F6A2,
- 0x1F6A3, 0x1F6A4, 0x1F6A5, 0x1F6A6, 0x1F6A7, 0x1F6A8, 0x1F6A9, 0x1F6AA, 0x1F6AB, 0x1F6AC,
- 0x1F6AD, 0x1F6AE, 0x1F6AF, 0x1F6B0, 0x1F6B1, 0x1F6B2, 0x1F6B3, 0x1F6B4, 0x1F6B5, 0x1F6B6,
- 0x1F6B7, 0x1F6B8, 0x1F6B9, 0x1F6BA, 0x1F6BB, 0x1F6BC, 0x1F6BD, 0x1F6BE, 0x1F6BF, 0x1F6C0,
- 0x1F6C1, 0x1F6C2, 0x1F6C3, 0x1F6C4, 0x1F6C5, 0x1F6CB, 0x1F6CC, 0x1F6CD, 0x1F6CE, 0x1F6CF,
- 0x1F6D0, 0x1F6D1, 0x1F6D2, 0x1F6E0, 0x1F6E1, 0x1F6E2, 0x1F6E3, 0x1F6E4, 0x1F6E5, 0x1F6E9,
- 0x1F6EB, 0x1F6EC, 0x1F6F0, 0x1F6F3, 0x1F6F4, 0x1F6F5, 0x1F6F6, 0x1F910, 0x1F911, 0x1F912,
- 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C,
- 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924, 0x1F925, 0x1F926, 0x1F927,
- 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939, 0x1F93A, 0x1F93B,
- 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943, 0x1F944, 0x1F945, 0x1F946,
- 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951, 0x1F952, 0x1F953, 0x1F954,
- 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B, 0x1F95C, 0x1F95D, 0x1F95E,
- 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986, 0x1F987, 0x1F988, 0x1F989,
- 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990, 0x1F991, 0x1F9C0
+ 0x2623, 0x2626, 0x262A, 0x262E, 0x262F, 0x2638, 0x2639, 0x263A, 0x2640, 0x2642, 0x2648,
+ 0x2649, 0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653,
+ 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267B, 0x267F, 0x2692, 0x2693, 0x2694, 0x2695,
+ 0x2696, 0x2697, 0x2699, 0x269B, 0x269C, 0x26A0, 0x26A1, 0x26AA, 0x26AB, 0x26B0, 0x26B1,
+ 0x26BD, 0x26BE, 0x26C4, 0x26C5, 0x26C8, 0x26CE, 0x26CF, 0x26D1, 0x26D3, 0x26D4, 0x26E9,
+ 0x26EA, 0x26F0, 0x26F1, 0x26F2, 0x26F3, 0x26F4, 0x26F5, 0x26F7, 0x26F8, 0x26F9, 0x26FA,
+ 0x26FD, 0x2702, 0x2705, 0x2708, 0x2709, 0x270A, 0x270B, 0x270C, 0x270D, 0x270F, 0x2712,
+ 0x2714, 0x2716, 0x271D, 0x2721, 0x2728, 0x2733, 0x2734, 0x2744, 0x2747, 0x274C, 0x274E,
+ 0x2753, 0x2754, 0x2755, 0x2757, 0x2763, 0x2764, 0x2795, 0x2796, 0x2797, 0x27A1, 0x27B0,
+ 0x27BF, 0x2934, 0x2935, 0x2B05, 0x2B06, 0x2B07, 0x2B1B, 0x2B1C, 0x2B50, 0x2B55, 0x3030,
+ 0x303D, 0x3297, 0x3299, 0x1F004, 0x1F0CF, 0x1F170, 0x1F171, 0x1F17E, 0x1F17F, 0x1F18E,
+ 0x1F191, 0x1F192, 0x1F193, 0x1F194, 0x1F195, 0x1F196, 0x1F197, 0x1F198, 0x1F199, 0x1F19A,
+ 0x1F1E6, 0x1F1E7, 0x1F1E8, 0x1F1E9, 0x1F1EA, 0x1F1EB, 0x1F1EC, 0x1F1ED, 0x1F1EE, 0x1F1EF,
+ 0x1F1F0, 0x1F1F1, 0x1F1F2, 0x1F1F3, 0x1F1F4, 0x1F1F5, 0x1F1F6, 0x1F1F7, 0x1F1F8, 0x1F1F9,
+ 0x1F1FA, 0x1F1FB, 0x1F1FC, 0x1F1FD, 0x1F1FE, 0x1F1FF, 0x1F201, 0x1F202, 0x1F21A, 0x1F22F,
+ 0x1F232, 0x1F233, 0x1F234, 0x1F235, 0x1F236, 0x1F237, 0x1F238, 0x1F239, 0x1F23A, 0x1F250,
+ 0x1F251, 0x1F300, 0x1F301, 0x1F302, 0x1F303, 0x1F304, 0x1F305, 0x1F306, 0x1F307, 0x1F308,
+ 0x1F309, 0x1F30A, 0x1F30B, 0x1F30C, 0x1F30D, 0x1F30E, 0x1F30F, 0x1F310, 0x1F311, 0x1F312,
+ 0x1F313, 0x1F314, 0x1F315, 0x1F316, 0x1F317, 0x1F318, 0x1F319, 0x1F31A, 0x1F31B, 0x1F31C,
+ 0x1F31D, 0x1F31E, 0x1F31F, 0x1F320, 0x1F321, 0x1F324, 0x1F325, 0x1F326, 0x1F327, 0x1F328,
+ 0x1F329, 0x1F32A, 0x1F32B, 0x1F32C, 0x1F32D, 0x1F32E, 0x1F32F, 0x1F330, 0x1F331, 0x1F332,
+ 0x1F333, 0x1F334, 0x1F335, 0x1F336, 0x1F337, 0x1F338, 0x1F339, 0x1F33A, 0x1F33B, 0x1F33C,
+ 0x1F33D, 0x1F33E, 0x1F33F, 0x1F340, 0x1F341, 0x1F342, 0x1F343, 0x1F344, 0x1F345, 0x1F346,
+ 0x1F347, 0x1F348, 0x1F349, 0x1F34A, 0x1F34B, 0x1F34C, 0x1F34D, 0x1F34E, 0x1F34F, 0x1F350,
+ 0x1F351, 0x1F352, 0x1F353, 0x1F354, 0x1F355, 0x1F356, 0x1F357, 0x1F358, 0x1F359, 0x1F35A,
+ 0x1F35B, 0x1F35C, 0x1F35D, 0x1F35E, 0x1F35F, 0x1F360, 0x1F361, 0x1F362, 0x1F363, 0x1F364,
+ 0x1F365, 0x1F366, 0x1F367, 0x1F368, 0x1F369, 0x1F36A, 0x1F36B, 0x1F36C, 0x1F36D, 0x1F36E,
+ 0x1F36F, 0x1F370, 0x1F371, 0x1F372, 0x1F373, 0x1F374, 0x1F375, 0x1F376, 0x1F377, 0x1F378,
+ 0x1F379, 0x1F37A, 0x1F37B, 0x1F37C, 0x1F37D, 0x1F37E, 0x1F37F, 0x1F380, 0x1F381, 0x1F382,
+ 0x1F383, 0x1F384, 0x1F385, 0x1F386, 0x1F387, 0x1F388, 0x1F389, 0x1F38A, 0x1F38B, 0x1F38C,
+ 0x1F38D, 0x1F38E, 0x1F38F, 0x1F390, 0x1F391, 0x1F392, 0x1F393, 0x1F396, 0x1F397, 0x1F399,
+ 0x1F39A, 0x1F39B, 0x1F39E, 0x1F39F, 0x1F3A0, 0x1F3A1, 0x1F3A2, 0x1F3A3, 0x1F3A4, 0x1F3A5,
+ 0x1F3A6, 0x1F3A7, 0x1F3A8, 0x1F3A9, 0x1F3AA, 0x1F3AB, 0x1F3AC, 0x1F3AD, 0x1F3AE, 0x1F3AF,
+ 0x1F3B0, 0x1F3B1, 0x1F3B2, 0x1F3B3, 0x1F3B4, 0x1F3B5, 0x1F3B6, 0x1F3B7, 0x1F3B8, 0x1F3B9,
+ 0x1F3BA, 0x1F3BB, 0x1F3BC, 0x1F3BD, 0x1F3BE, 0x1F3BF, 0x1F3C0, 0x1F3C1, 0x1F3C2, 0x1F3C3,
+ 0x1F3C4, 0x1F3C5, 0x1F3C6, 0x1F3C7, 0x1F3C8, 0x1F3C9, 0x1F3CA, 0x1F3CB, 0x1F3CC, 0x1F3CD,
+ 0x1F3CE, 0x1F3CF, 0x1F3D0, 0x1F3D1, 0x1F3D2, 0x1F3D3, 0x1F3D4, 0x1F3D5, 0x1F3D6, 0x1F3D7,
+ 0x1F3D8, 0x1F3D9, 0x1F3DA, 0x1F3DB, 0x1F3DC, 0x1F3DD, 0x1F3DE, 0x1F3DF, 0x1F3E0, 0x1F3E1,
+ 0x1F3E2, 0x1F3E3, 0x1F3E4, 0x1F3E5, 0x1F3E6, 0x1F3E7, 0x1F3E8, 0x1F3E9, 0x1F3EA, 0x1F3EB,
+ 0x1F3EC, 0x1F3ED, 0x1F3EE, 0x1F3EF, 0x1F3F0, 0x1F3F3, 0x1F3F4, 0x1F3F5, 0x1F3F7, 0x1F3F8,
+ 0x1F3F9, 0x1F3FA, 0x1F3FB, 0x1F3FC, 0x1F3FD, 0x1F3FE, 0x1F3FF, 0x1F400, 0x1F401, 0x1F402,
+ 0x1F403, 0x1F404, 0x1F405, 0x1F406, 0x1F407, 0x1F408, 0x1F409, 0x1F40A, 0x1F40B, 0x1F40C,
+ 0x1F40D, 0x1F40E, 0x1F40F, 0x1F410, 0x1F411, 0x1F412, 0x1F413, 0x1F414, 0x1F415, 0x1F416,
+ 0x1F417, 0x1F418, 0x1F419, 0x1F41A, 0x1F41B, 0x1F41C, 0x1F41D, 0x1F41E, 0x1F41F, 0x1F420,
+ 0x1F421, 0x1F422, 0x1F423, 0x1F424, 0x1F425, 0x1F426, 0x1F427, 0x1F428, 0x1F429, 0x1F42A,
+ 0x1F42B, 0x1F42C, 0x1F42D, 0x1F42E, 0x1F42F, 0x1F430, 0x1F431, 0x1F432, 0x1F433, 0x1F434,
+ 0x1F435, 0x1F436, 0x1F437, 0x1F438, 0x1F439, 0x1F43A, 0x1F43B, 0x1F43C, 0x1F43D, 0x1F43E,
+ 0x1F43F, 0x1F440, 0x1F441, 0x1F442, 0x1F443, 0x1F444, 0x1F445, 0x1F446, 0x1F447, 0x1F448,
+ 0x1F449, 0x1F44A, 0x1F44B, 0x1F44C, 0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F451, 0x1F452,
+ 0x1F453, 0x1F454, 0x1F455, 0x1F456, 0x1F457, 0x1F458, 0x1F459, 0x1F45A, 0x1F45B, 0x1F45C,
+ 0x1F45D, 0x1F45E, 0x1F45F, 0x1F460, 0x1F461, 0x1F462, 0x1F463, 0x1F464, 0x1F465, 0x1F466,
+ 0x1F467, 0x1F468, 0x1F469, 0x1F46A, 0x1F46B, 0x1F46C, 0x1F46D, 0x1F46E, 0x1F46F, 0x1F470,
+ 0x1F471, 0x1F472, 0x1F473, 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F479, 0x1F47A,
+ 0x1F47B, 0x1F47C, 0x1F47D, 0x1F47E, 0x1F47F, 0x1F480, 0x1F481, 0x1F482, 0x1F483, 0x1F484,
+ 0x1F485, 0x1F486, 0x1F487, 0x1F488, 0x1F489, 0x1F48A, 0x1F48B, 0x1F48C, 0x1F48D, 0x1F48E,
+ 0x1F48F, 0x1F490, 0x1F491, 0x1F492, 0x1F493, 0x1F494, 0x1F495, 0x1F496, 0x1F497, 0x1F498,
+ 0x1F499, 0x1F49A, 0x1F49B, 0x1F49C, 0x1F49D, 0x1F49E, 0x1F49F, 0x1F4A0, 0x1F4A1, 0x1F4A2,
+ 0x1F4A3, 0x1F4A4, 0x1F4A5, 0x1F4A6, 0x1F4A7, 0x1F4A8, 0x1F4A9, 0x1F4AA, 0x1F4AB, 0x1F4AC,
+ 0x1F4AD, 0x1F4AE, 0x1F4AF, 0x1F4B0, 0x1F4B1, 0x1F4B2, 0x1F4B3, 0x1F4B4, 0x1F4B5, 0x1F4B6,
+ 0x1F4B7, 0x1F4B8, 0x1F4B9, 0x1F4BA, 0x1F4BB, 0x1F4BC, 0x1F4BD, 0x1F4BE, 0x1F4BF, 0x1F4C0,
+ 0x1F4C1, 0x1F4C2, 0x1F4C3, 0x1F4C4, 0x1F4C5, 0x1F4C6, 0x1F4C7, 0x1F4C8, 0x1F4C9, 0x1F4CA,
+ 0x1F4CB, 0x1F4CC, 0x1F4CD, 0x1F4CE, 0x1F4CF, 0x1F4D0, 0x1F4D1, 0x1F4D2, 0x1F4D3, 0x1F4D4,
+ 0x1F4D5, 0x1F4D6, 0x1F4D7, 0x1F4D8, 0x1F4D9, 0x1F4DA, 0x1F4DB, 0x1F4DC, 0x1F4DD, 0x1F4DE,
+ 0x1F4DF, 0x1F4E0, 0x1F4E1, 0x1F4E2, 0x1F4E3, 0x1F4E4, 0x1F4E5, 0x1F4E6, 0x1F4E7, 0x1F4E8,
+ 0x1F4E9, 0x1F4EA, 0x1F4EB, 0x1F4EC, 0x1F4ED, 0x1F4EE, 0x1F4EF, 0x1F4F0, 0x1F4F1, 0x1F4F2,
+ 0x1F4F3, 0x1F4F4, 0x1F4F5, 0x1F4F6, 0x1F4F7, 0x1F4F8, 0x1F4F9, 0x1F4FA, 0x1F4FB, 0x1F4FC,
+ 0x1F4FD, 0x1F4FF, 0x1F500, 0x1F501, 0x1F502, 0x1F503, 0x1F504, 0x1F505, 0x1F506, 0x1F507,
+ 0x1F508, 0x1F509, 0x1F50A, 0x1F50B, 0x1F50C, 0x1F50D, 0x1F50E, 0x1F50F, 0x1F510, 0x1F511,
+ 0x1F512, 0x1F513, 0x1F514, 0x1F515, 0x1F516, 0x1F517, 0x1F518, 0x1F519, 0x1F51A, 0x1F51B,
+ 0x1F51C, 0x1F51D, 0x1F51E, 0x1F51F, 0x1F520, 0x1F521, 0x1F522, 0x1F523, 0x1F524, 0x1F525,
+ 0x1F526, 0x1F527, 0x1F528, 0x1F529, 0x1F52A, 0x1F52B, 0x1F52C, 0x1F52D, 0x1F52E, 0x1F52F,
+ 0x1F530, 0x1F531, 0x1F532, 0x1F533, 0x1F534, 0x1F535, 0x1F536, 0x1F537, 0x1F538, 0x1F539,
+ 0x1F53A, 0x1F53B, 0x1F53C, 0x1F53D, 0x1F549, 0x1F54A, 0x1F54B, 0x1F54C, 0x1F54D, 0x1F54E,
+ 0x1F550, 0x1F551, 0x1F552, 0x1F553, 0x1F554, 0x1F555, 0x1F556, 0x1F557, 0x1F558, 0x1F559,
+ 0x1F55A, 0x1F55B, 0x1F55C, 0x1F55D, 0x1F55E, 0x1F55F, 0x1F560, 0x1F561, 0x1F562, 0x1F563,
+ 0x1F564, 0x1F565, 0x1F566, 0x1F567, 0x1F56F, 0x1F570, 0x1F573, 0x1F574, 0x1F575, 0x1F576,
+ 0x1F577, 0x1F578, 0x1F579, 0x1F57A, 0x1F587, 0x1F58A, 0x1F58B, 0x1F58C, 0x1F58D, 0x1F590,
+ 0x1F595, 0x1F596, 0x1F5A4, 0x1F5A5, 0x1F5A8, 0x1F5B1, 0x1F5B2, 0x1F5BC, 0x1F5C2, 0x1F5C3,
+ 0x1F5C4, 0x1F5D1, 0x1F5D2, 0x1F5D3, 0x1F5DC, 0x1F5DD, 0x1F5DE, 0x1F5E1, 0x1F5E3, 0x1F5E8,
+ 0x1F5EF, 0x1F5F3, 0x1F5FA, 0x1F5FB, 0x1F5FC, 0x1F5FD, 0x1F5FE, 0x1F5FF, 0x1F600, 0x1F601,
+ 0x1F602, 0x1F603, 0x1F604, 0x1F605, 0x1F606, 0x1F607, 0x1F608, 0x1F609, 0x1F60A, 0x1F60B,
+ 0x1F60C, 0x1F60D, 0x1F60E, 0x1F60F, 0x1F610, 0x1F611, 0x1F612, 0x1F613, 0x1F614, 0x1F615,
+ 0x1F616, 0x1F617, 0x1F618, 0x1F619, 0x1F61A, 0x1F61B, 0x1F61C, 0x1F61D, 0x1F61E, 0x1F61F,
+ 0x1F620, 0x1F621, 0x1F622, 0x1F623, 0x1F624, 0x1F625, 0x1F626, 0x1F627, 0x1F628, 0x1F629,
+ 0x1F62A, 0x1F62B, 0x1F62C, 0x1F62D, 0x1F62E, 0x1F62F, 0x1F630, 0x1F631, 0x1F632, 0x1F633,
+ 0x1F634, 0x1F635, 0x1F636, 0x1F637, 0x1F638, 0x1F639, 0x1F63A, 0x1F63B, 0x1F63C, 0x1F63D,
+ 0x1F63E, 0x1F63F, 0x1F640, 0x1F641, 0x1F642, 0x1F643, 0x1F644, 0x1F645, 0x1F646, 0x1F647,
+ 0x1F648, 0x1F649, 0x1F64A, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F680, 0x1F681,
+ 0x1F682, 0x1F683, 0x1F684, 0x1F685, 0x1F686, 0x1F687, 0x1F688, 0x1F689, 0x1F68A, 0x1F68B,
+ 0x1F68C, 0x1F68D, 0x1F68E, 0x1F68F, 0x1F690, 0x1F691, 0x1F692, 0x1F693, 0x1F694, 0x1F695,
+ 0x1F696, 0x1F697, 0x1F698, 0x1F699, 0x1F69A, 0x1F69B, 0x1F69C, 0x1F69D, 0x1F69E, 0x1F69F,
+ 0x1F6A0, 0x1F6A1, 0x1F6A2, 0x1F6A3, 0x1F6A4, 0x1F6A5, 0x1F6A6, 0x1F6A7, 0x1F6A8, 0x1F6A9,
+ 0x1F6AA, 0x1F6AB, 0x1F6AC, 0x1F6AD, 0x1F6AE, 0x1F6AF, 0x1F6B0, 0x1F6B1, 0x1F6B2, 0x1F6B3,
+ 0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6B7, 0x1F6B8, 0x1F6B9, 0x1F6BA, 0x1F6BB, 0x1F6BC, 0x1F6BD,
+ 0x1F6BE, 0x1F6BF, 0x1F6C0, 0x1F6C1, 0x1F6C2, 0x1F6C3, 0x1F6C4, 0x1F6C5, 0x1F6CB, 0x1F6CC,
+ 0x1F6CD, 0x1F6CE, 0x1F6CF, 0x1F6D0, 0x1F6D1, 0x1F6D2, 0x1F6E0, 0x1F6E1, 0x1F6E2, 0x1F6E3,
+ 0x1F6E4, 0x1F6E5, 0x1F6E9, 0x1F6EB, 0x1F6EC, 0x1F6F0, 0x1F6F3, 0x1F6F4, 0x1F6F5, 0x1F6F6,
+ 0x1F910, 0x1F911, 0x1F912, 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919,
+ 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924,
+ 0x1F925, 0x1F926, 0x1F927, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938,
+ 0x1F939, 0x1F93A, 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943,
+ 0x1F944, 0x1F945, 0x1F946, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951,
+ 0x1F952, 0x1F953, 0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B,
+ 0x1F95C, 0x1F95D, 0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986,
+ 0x1F987, 0x1F988, 0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990,
+ 0x1F991, 0x1F9C0
};
// See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 3770a45..2f327f3 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -129,8 +129,8 @@
// The offset is immediately before a variation selector.
final int STATE_BEFORE_VS = 6;
- // The offset is immediately before a ZWJ emoji.
- final int STATE_BEFORE_ZWJ_EMOJI = 7;
+ // The offset is immediately before an emoji.
+ final int STATE_BEFORE_EMOJI = 7;
// The offset is immediately before a ZWJ that were seen before a ZWJ emoji.
final int STATE_BEFORE_ZWJ = 8;
// The offset is immediately before a variation selector and a ZWJ that were seen before a
@@ -169,7 +169,7 @@
} else if (codePoint == Emoji.COMBINING_ENCLOSING_KEYCAP) {
state = STATE_BEFORE_KEYCAP;
} else if (Emoji.isEmoji(codePoint)) {
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
} else {
state = STATE_FINISHED;
}
@@ -232,7 +232,7 @@
case STATE_BEFORE_VS:
if (Emoji.isEmoji(codePoint)) {
deleteCharCount += Character.charCount(codePoint);
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
break;
}
@@ -242,7 +242,7 @@
}
state = STATE_FINISHED;
break;
- case STATE_BEFORE_ZWJ_EMOJI:
+ case STATE_BEFORE_EMOJI:
if (codePoint == Emoji.ZERO_WIDTH_JOINER) {
state = STATE_BEFORE_ZWJ;
} else {
@@ -252,7 +252,8 @@
case STATE_BEFORE_ZWJ:
if (Emoji.isEmoji(codePoint)) {
deleteCharCount += Character.charCount(codePoint) + 1; // +1 for ZWJ.
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = Emoji.isEmojiModifier(codePoint) ?
+ STATE_BEFORE_EMOJI_MODIFIER : STATE_BEFORE_EMOJI;
} else if (isVariationSelector(codePoint)) {
lastSeenVSCharCount = Character.charCount(codePoint);
state = STATE_BEFORE_VS_AND_ZWJ;
@@ -265,7 +266,7 @@
// +1 for ZWJ.
deleteCharCount += lastSeenVSCharCount + 1 + Character.charCount(codePoint);
lastSeenVSCharCount = 0;
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
} else {
state = STATE_FINISHED;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 898cf77..85092ad 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -768,6 +768,21 @@
return false;
}
+ // Don't count glyphs that are the recommended "space" glyph and are zero width.
+ // This logic makes assumptions about HarfBuzz layout, but does correctly handle
+ // cases where ligatures form and zero width space glyphs are left in as
+ // placeholders.
+ static size_t countNonSpaceGlyphs(const Layout& layout) {
+ size_t count = 0;
+ static unsigned int kSpaceGlyphId = 3;
+ for (size_t i = 0; i < layout.nGlyphs(); i++) {
+ if (layout.getGlyphId(i) != kSpaceGlyphId || layout.getCharAdvance(i) != 0.0) {
+ count++;
+ }
+ }
+ return count;
+ }
+
// Returns true if the given string is exact one pair of regional indicators.
static bool isFlag(const jchar* str, size_t length) {
const jchar RI_LEAD_SURROGATE = 0xD83C;
@@ -831,7 +846,7 @@
Layout layout;
MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
str.size());
- size_t nGlyphs = layout.nGlyphs();
+ size_t nGlyphs = countNonSpaceGlyphs(layout);
if (nGlyphs != 1 && nChars > 1) {
// multiple-character input, and was not a ligature
// TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index a9fa4dd..fd686b9 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -170,10 +170,27 @@
backspace(state, 0);
state.assertEquals("|");
+ state.setByString("U+1F469 U+200D U+1F373 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F487 U+200D U+2640 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F487 U+200D U+2640 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
state.setByString("U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 |");
backspace(state, 0);
state.assertEquals("|");
+ // Emoji modifier can be appended to the first emoji.
+ state.setByString("U+1F469 U+1F3FB U+200D U+1F4BC |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
// End with ZERO WIDTH JOINER
state.setByString("U+1F441 U+200D |");
backspace(state, 0);
@@ -445,13 +462,6 @@
backspace(state, 0);
state.assertEquals("|");
- // Emoji modifier + ZERO WIDTH JOINER
- state.setByString("U+1F466 U+1F3FB U+200D U+1F469 |");
- backspace(state, 0);
- state.assertEquals("U+1F466 |");
- backspace(state, 0);
- state.assertEquals("|");
-
// Regional indicator symbol + Emoji modifier
state.setByString("U+1F1FA U+1F3FB |");
backspace(state, 0);
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 39b8d3d..84451ba 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -530,14 +530,14 @@
}
void ClipArea::applyTransformToRegion(const Matrix4& transform, SkRegion* region) {
- if (transform.isSimple() && !transform.isPureTranslate()) {
+ if (transform.rectToRect() && !transform.isPureTranslate()) {
// handle matrices with scale manually by mapping each rect
SkRegion other;
SkRegion::Iterator it(*region);
while (!it.done()) {
Rect rect(it.rect());
transform.mapRect(rect);
- rect.roundOut();
+ rect.snapGeometryToPixelBoundaries(true);
other.op(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kUnion_Op);
it.next();
}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index afabd35..d4d7919 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -334,5 +334,14 @@
EXPECT_EQ(SkIRect::MakeLTRB(12, 26, 16, 32), region.getBounds());
}
+TEST(ClipArea, applyTransformToRegion_rotate90) {
+ SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
+ Matrix4 transform;
+ transform.loadRotate(90);
+ ClipArea::applyTransformToRegion(transform, ®ion);
+ EXPECT_TRUE(region.isRect());
+ EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 542dced..264944f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -133,9 +133,10 @@
<p class=note>
Note that on some devices the slice-height is advertised as 0. This could mean either that the
slice-height is the same as the frame height, or that the slice-height is the frame height
- aligned to some value (usually a power of 2). Unfortunately, there is no way to tell the actual
- slice height in this case. Furthermore, the vertical stride of the {@code U} plane in planar
- formats is also not specified or defined, though usually it is half of the slice height.
+ aligned to some value (usually a power of 2). Unfortunately, there is no standard and simple way
+ to tell the actual slice height in this case. Furthermore, the vertical stride of the {@code U}
+ plane in planar formats is also not specified or defined, though usually it is half of the slice
+ height.
<p>
The {@link MediaFormat#KEY_WIDTH} and {@link MediaFormat#KEY_HEIGHT} keys specify the size of the
video frames; however, for most encondings the video (picture) only occupies a portion of the
@@ -620,8 +621,9 @@
mode} will be automatically applied with one exception:
<p class=note>
Prior to the {@link android.os.Build.VERSION_CODES#M} release, software decoders may not
- have applied the rotation when being rendered onto a Surface. Unfortunately, there is no way to
- identify software decoders, or if they apply the rotation other than by trying it out.
+ have applied the rotation when being rendered onto a Surface. Unfortunately, there is no standard
+ and simple way to identify software decoders, or if they apply the rotation other than by trying
+ it out.
<p>
There are also some caveats.
<p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index d7a18d9..d74aa81 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -49,12 +49,18 @@
* <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td>required for <b>encoders</b>,
* optional for <b>decoders</b></td></tr>
* <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr>
- * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer (or Float)</td><td><b>encoder-only</b>,
+ * time-interval between key frames.
+ * Float support added in {@link android.os.Build.VERSION_CODES#N_MR1}</td></tr>
* <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
* <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
* <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
- * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
- * <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>video decoder rendering to a surface only</b></td></tr>
+ * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>encoder in surface-mode
+ * only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_PUSH_BLANK_BUFFERS_ON_STOP}</td><td>Integer(1)</td><td><b>decoder rendering
+ * to a surface only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_TEMPORAL_LAYERING}</td><td>String</td><td><b>encoder only</b>, optional,
+ * temporal-layering schema</td></tr>
* </table>
* Specify both {@link #KEY_MAX_WIDTH} and {@link #KEY_MAX_HEIGHT} to enable
* adaptive playback (seamless resolution change) for a video decoder that
@@ -258,9 +264,20 @@
public static final String KEY_CAPTURE_RATE = "capture-rate";
/**
- * A key describing the frequency of I frames expressed in secs
- * between I frames.
- * The associated value is an integer.
+ * A key describing the frequency of key frames expressed in seconds between key frames.
+ * <p>
+ * This key is used by video encoders.
+ * A negative value means no key frames are requested after the first frame.
+ * A zero value means a stream containing all key frames is requested.
+ * <p class=note>
+ * Most video encoders will convert this value of the number of non-key-frames between
+ * key-frames, using the {@linkplain #KEY_FRAME_RATE frame rate} information; therefore,
+ * if the actual frame rate differs (e.g. input frames are dropped or the frame rate
+ * changes), the <strong>time interval</strong> between key frames will not be the
+ * configured value.
+ * <p>
+ * The associated value is an integer (or float since
+ * {@link android.os.Build.VERSION_CODES#N_MR1}).
*/
public static final String KEY_I_FRAME_INTERVAL = "i-frame-interval";
@@ -280,12 +297,18 @@
/**
* A key describing the temporal layering schema. This is an optional parameter
- * that applies only to video encoders. Use {@link MediaCodec#getInputFormat}
+ * that applies only to video encoders. Use {@link MediaCodec#getOutputFormat}
* after {@link MediaCodec#configure configure} to query if the encoder supports
- * the desired schema. Supported values are {@code webrtc.vp8.1-layer},
- * {@code webrtc.vp8.2-layer}, {@code webrtc.vp8.3-layer}, and {@code none}.
- * If the encoder does not support temporal layering, the input format will
- * not have an entry with this key.
+ * the desired schema. Supported values are {@code webrtc.vp8.N-layer},
+ * {@code android.generic.N}, {@code android.generic.N+M} and {@code none}, where
+ * {@code N} denotes the total number of non-bidirectional layers (which must be at least 1)
+ * and {@code M} denotes the total number of bidirectional layers (which must be non-negative).
+ * <p class=note>{@code android.generic.*} schemas have been added in {@link
+ * android.os.Build.VERSION_CODES#N_MR1}.
+ * <p>
+ * The encoder may support fewer temporal layers, in which case the output format
+ * will contain the configured schema. If the encoder does not support temporal
+ * layering, the output format will not have an entry with this key.
* The associated value is a string.
*/
public static final String KEY_TEMPORAL_LAYERING = "ts-schema";
diff --git a/packages/Keyguard/res/values-my-rMM/dimens.xml b/packages/Keyguard/res/values-my-rMM/dimens.xml
new file mode 100644
index 0000000..21b2a46
--- /dev/null
+++ b/packages/Keyguard/res/values-my-rMM/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <dimen name="bottom_text_spacing_digital">4dp</dimen>
+</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 9d1df26..e1657c7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -127,6 +127,11 @@
super.onConfigurationChanged(newConfig);
mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
+ // Some layouts like burmese have a different margin for the clock
+ MarginLayoutParams layoutParams = (MarginLayoutParams) mClockView.getLayoutParams();
+ layoutParams.bottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.bottom_text_spacing_digital);
+ mClockView.setLayoutParams(layoutParams);
mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 4b82279..64f205d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -78,7 +79,6 @@
private static final int CAP_HEIGHT = 1456;
private static final int FONT_HEIGHT = 2163;
- private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
private static final String COUNTER_PANEL_OPEN = "panel_open";
@@ -1376,8 +1376,7 @@
int min = mStatusBarMinHeight;
if (mStatusBar.getBarState() != StatusBarState.KEYGUARD
&& mNotificationStackScroller.getNotGoneChildCount() == 0) {
- int minHeight = (int) ((mQsMinExpansionHeight + getOverExpansionAmount())
- * HEADER_RUBBERBAND_FACTOR);
+ int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
}
int maxHeight;
@@ -1552,15 +1551,8 @@
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
return 0;
}
- if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
- return Math.min(0, mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight);
- }
- float stackTranslation = mNotificationStackScroller.getStackTranslation();
- float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
- if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
- translation = mNotificationStackScroller.getTopPadding() + stackTranslation
- - mQsMinExpansionHeight;
- }
+ float translation = NotificationUtils.interpolate(-mQsMinExpansionHeight, 0,
+ mNotificationStackScroller.getAppearFraction(mExpandedHeight));
return Math.min(0, translation);
}
@@ -1968,7 +1960,7 @@
if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
return mNotificationStackScroller.getPeekHeight();
} else {
- return mQsMinExpansionHeight * HEADER_RUBBERBAND_FACTOR;
+ return mQsMinExpansionHeight;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fb7afc5..482c698 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2586,7 +2586,7 @@
@Override
public void handleSystemNavigationKey(int key) {
if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
- if (!panelsEnabled()) {
+ if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 970fed0..c175180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -112,6 +112,10 @@
notifyKeyguardChanged();
}
+ public boolean isDeviceInteractive() {
+ return mKeyguardUpdateMonitor.isDeviceInteractive();
+ }
+
private void updateCanSkipBouncerState() {
mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e00674a..71b349f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -668,30 +668,74 @@
public void setStackHeight(float height) {
mLastSetStackHeight = height;
setIsExpanded(height > 0.0f);
- int newStackHeight = (int) height;
- int minStackHeight = getLayoutMinHeight();
int stackHeight;
- float paddingOffset;
- boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
- int normalUnfoldPositionStart = trackingHeadsUp
- ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
- : minStackHeight;
- if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart
- || getNotGoneChildCount() == 0) {
- paddingOffset = mTopPaddingOverflow;
- stackHeight = newStackHeight;
+ float translationY;
+ float appearEndPosition = getAppearEndPosition();
+ float appearStartPosition = getAppearStartPosition();
+ if (height >= appearEndPosition) {
+ translationY = mTopPaddingOverflow;
+ stackHeight = (int) height;
} else {
- int translationY;
- translationY = newStackHeight - normalUnfoldPositionStart;
- paddingOffset = translationY - mTopPadding;
- stackHeight = (int) (height - (translationY - mTopPadding));
+ float appearFraction = getAppearFraction(height);
+ if (appearFraction >= 0) {
+ translationY = NotificationUtils.interpolate(getExpandTranslationStart(), 0,
+ appearFraction);
+ } else {
+ // This may happen when pushing up a heads up. We linearly push it up from the
+ // start
+ translationY = height - appearStartPosition + getExpandTranslationStart();
+ }
+ stackHeight = (int) (height - translationY);
}
if (stackHeight != mCurrentStackHeight) {
mCurrentStackHeight = stackHeight;
updateAlgorithmHeightAndPadding();
requestChildrenUpdate();
}
- setStackTranslation(paddingOffset);
+ setStackTranslation(translationY);
+ }
+
+ /**
+ * @return The translation at the beginning when expanding.
+ * Measured relative to the resting position.
+ */
+ private float getExpandTranslationStart() {
+ int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
+ ? 0 : -getFirstChildMinHeight();
+ return startPosition - mTopPadding;
+ }
+
+ /**
+ * @return the position from where the appear transition starts when expanding.
+ * Measured in absolute height.
+ */
+ private float getAppearStartPosition() {
+ return mTrackingHeadsUp
+ ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
+ : 0;
+ }
+
+ /**
+ * @return the position from where the appear transition ends when expanding.
+ * Measured in absolute height.
+ */
+ private float getAppearEndPosition() {
+ int firstItemHeight = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
+ ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
+ + mBottomStackSlowDownHeight
+ : getLayoutMinHeight();
+ return firstItemHeight + mTopPadding + mTopPaddingOverflow;
+ }
+
+ /**
+ * @param height the height of the panel
+ * @return the fraction of the appear animation that has been performed
+ */
+ public float getAppearFraction(float height) {
+ float appearEndPosition = getAppearEndPosition();
+ float appearStartPosition = getAppearStartPosition();
+ return (height - appearStartPosition)
+ / (appearEndPosition - appearStartPosition);
}
public float getStackTranslation() {
@@ -2096,6 +2140,12 @@
}
public int getLayoutMinHeight() {
+ int firstChildMinHeight = getFirstChildMinHeight();
+ return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+ mMaxLayoutHeight - mTopPadding);
+ }
+
+ private int getFirstChildMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
int firstChildMinHeight = firstChild != null
? firstChild.getIntrinsicHeight()
@@ -2105,8 +2155,7 @@
if (mOwnScrollY > 0) {
firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
}
- return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
- mMaxLayoutHeight - mTopPadding);
+ return firstChildMinHeight;
}
public float getTopPaddingOverflow() {
@@ -2605,6 +2654,10 @@
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
: AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+ if (row.isChildInGroup()) {
+ // We can otherwise get stuck in there if it was just isolated
+ row.setHeadsupDisappearRunning(false);
+ }
} else {
StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
if (viewState == null) {
@@ -3101,7 +3154,13 @@
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) view).setHeadsupDisappearRunning(false);
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ row.setHeadsupDisappearRunning(false);
+ if (row.isSummaryWithChildren()) {
+ for (ExpandableNotificationRow child : row.getNotificationChildren()) {
+ child.setHeadsupDisappearRunning(false);
+ }
+ }
}
}
}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 97efed0..05207b9 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -114,13 +114,17 @@
imageStage.delete();
lockImageStage.delete();
- Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
- fullBackupFile(infoStage, data);
- Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
- fullBackupFile(imageStage, data);
+ if (mWallpaperInfo.exists()) {
+ Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+ fullBackupFile(infoStage, data);
+ }
+ if (mWallpaperFile.exists()) {
+ Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+ fullBackupFile(imageStage, data);
+ }
// Don't try to store the lock image if we overran our quota last time
- if (!mQuotaExceeded) {
+ if (mLockWallpaperFile.exists() && !mQuotaExceeded) {
Os.link(mLockWallpaperFile.getCanonicalPath(), lockImageStage.getCanonicalPath());
fullBackupFile(lockImageStage, data);
}
@@ -130,7 +134,7 @@
}
}
} catch (Exception e) {
- Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+ Slog.e(TAG, "Unable to back up wallpaper", e);
} finally {
if (DEBUG) {
Slog.v(TAG, "Removing backup stage links");
@@ -173,6 +177,9 @@
final File lockImageStage = new File (filesDir, LOCK_IMAGE_STAGE);
try {
+ // First off, revert to the factory state
+ mWm.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+
// It is valid for the imagery to be absent; it means that we were not permitted
// to back up the original image on the source device, or there was no user-supplied
// wallpaper image present.
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5ce8c9e..d10080b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -5707,16 +5707,21 @@
}
void tearDownPipes() {
- if (mPipes != null) {
- try {
- mPipes[0].close();
- mPipes[0] = null;
- mPipes[1].close();
- mPipes[1] = null;
- } catch (IOException e) {
- Slog.w(TAG, "Couldn't close agent pipes", e);
+ // Teardown might arise from the inline restore processing or from the asynchronous
+ // timeout mechanism, and these might race. Make sure we don't try to close and
+ // null out the pipes twice.
+ synchronized (this) {
+ if (mPipes != null) {
+ try {
+ mPipes[0].close();
+ mPipes[0] = null;
+ mPipes[1].close();
+ mPipes[1] = null;
+ } catch (IOException e) {
+ Slog.w(TAG, "Couldn't close agent pipes", e);
+ }
+ mPipes = null;
}
- mPipes = null;
}
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index eaf317a..7ea8f1f 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -41,6 +41,7 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.os.BackgroundThread;
+import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import java.util.ArrayList;
@@ -240,12 +241,6 @@
}
mPinnedCameraFiles.add(pf);
- //find the location of the odex based on the location of the APK
- int lastPeriod = camAPK.lastIndexOf('.');
- int lastSlash = camAPK.lastIndexOf('/', lastPeriod);
- String base = camAPK.substring(0, lastSlash);
- String appName = camAPK.substring(lastSlash + 1, lastPeriod);
-
// determine the ABI from either ApplicationInfo or Build
String arch = "arm";
if (cameraInfo.primaryCpuAbi != null
@@ -256,8 +251,18 @@
arch = arch + "64";
}
}
- String odex = base + "/oat/" + arch + "/" + appName + ".odex";
- //not all apps have odex files, so not pinning the odex is not a fatal error
+
+ // get the path to the odex or oat file
+ String baseCodePath = cameraInfo.getBaseCodePath();
+ String odex = null;
+ try {
+ odex = DexFile.getDexFileOutputPath(baseCodePath, arch);
+ } catch (IOException ioe) {}
+ if (odex == null) {
+ return true;
+ }
+
+ //not pinning the oat/odex is not a fatal error
pf = pinFile(odex, 0, 0, MAX_CAMERA_PIN_SIZE);
if (pf != null) {
mPinnedCameraFiles.add(pf);
@@ -265,6 +270,7 @@
Slog.i(TAG, "Pinned " + pf.mFilename);
}
}
+
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4169206..8716811 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -140,7 +140,6 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -18876,15 +18875,6 @@
null, AppOpsManager.OP_NONE, null, false, false,
MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
- // Tell the shortcut manager that the system locale changed. It needs to know
- // it before any other apps receive ACTION_LOCALE_CHANGED, which is why
- // we "push" from here, rather than having the service listen to the broadcast.
- final ShortcutServiceInternal shortcutService =
- LocalServices.getService(ShortcutServiceInternal.class);
- if (shortcutService != null) {
- shortcutService.onSystemLocaleChangedNoLock();
- }
-
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (!mProcessesReady) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 12310e3..b6c8d5d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -450,8 +450,6 @@
private int setWifiTethering(final boolean enable) {
synchronized (mPublicSync) {
- // Note that we're maintaining a predicate that mWifiTetherRequested always matches
- // our last request to WifiManager re: its AP enabled status.
mWifiTetherRequested = enable;
final WifiManager wifiManager =
(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
@@ -794,10 +792,6 @@
}
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
synchronized (Tethering.this.mPublicSync) {
- if (!mWifiTetherRequested) {
- // We only care when we're trying to tether via our WiFi interface.
- return;
- }
int curState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
WifiManager.WIFI_AP_STATE_DISABLED);
switch (curState) {
@@ -805,8 +799,10 @@
// We can see this state on the way to both enabled and failure states.
break;
case WifiManager.WIFI_AP_STATE_ENABLED:
- // Tell an appropriate interface state machine that it should tether.
- tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
+ // When the AP comes up and we've been requested to tether it, do so.
+ if (mWifiTetherRequested) {
+ tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
+ }
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
case WifiManager.WIFI_AP_STATE_DISABLING:
@@ -816,10 +812,20 @@
Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" +
curState);
}
- // Tell an appropriate interface state machine that
- // it needs to tear itself down.
- tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_WIFI);
- setWifiTethering(false);
+ // Tell appropriate interface state machines that they should tear
+ // themselves down.
+ for (int i = 0; i < mTetherStates.size(); i++) {
+ TetherInterfaceStateMachine tism =
+ mTetherStates.valueAt(i).mStateMachine;
+ if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ tism.sendMessage(
+ TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+ break; // There should be at most one of these.
+ }
+ }
+ // Regardless of whether we requested this transition, the AP has gone
+ // down. Don't try to tether again unless we're requested to do so.
+ mWifiTetherRequested = false;
break;
}
}
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 006747b..1f4ee9b 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -22,6 +22,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -56,7 +58,10 @@
0, 0, 0, 1
};
+ private final Handler mHandler;
+
private int mCurrentUser = UserHandle.USER_NULL;
+ private ContentObserver mUserSetupObserver;
private boolean mBootCompleted;
private NightDisplayController mController;
@@ -65,6 +70,7 @@
public NightDisplayService(Context context) {
super(context);
+ mHandler = new Handler(Looper.getMainLooper());
}
@Override
@@ -73,15 +79,23 @@
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ mBootCompleted = true;
+
+ // Register listeners now that boot is complete.
+ if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
+ setUp();
+ }
+ }
+ }
+
+ @Override
public void onStartUser(int userHandle) {
super.onStartUser(userHandle);
- // Register listeners for the new user.
if (mCurrentUser == UserHandle.USER_NULL) {
- mCurrentUser = userHandle;
- if (mBootCompleted) {
- setUpNightMode();
- }
+ onUserChanged(userHandle);
}
}
@@ -89,44 +103,60 @@
public void onSwitchUser(int userHandle) {
super.onSwitchUser(userHandle);
- // Unregister listeners for the old user.
- if (mBootCompleted && mCurrentUser != UserHandle.USER_NULL) {
- tearDownNightMode();
- }
-
- // Register listeners for the new user.
- mCurrentUser = userHandle;
- if (mBootCompleted) {
- setUpNightMode();
- }
+ onUserChanged(userHandle);
}
@Override
public void onStopUser(int userHandle) {
super.onStopUser(userHandle);
- // Unregister listeners for the old user.
if (mCurrentUser == userHandle) {
- if (mBootCompleted) {
- tearDownNightMode();
- }
- mCurrentUser = UserHandle.USER_NULL;
+ onUserChanged(UserHandle.USER_NULL);
}
}
- @Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_BOOT_COMPLETED) {
- mBootCompleted = true;
+ private void onUserChanged(int userHandle) {
+ final ContentResolver cr = getContext().getContentResolver();
- // Register listeners now that boot is complete.
- if (mCurrentUser != UserHandle.USER_NULL) {
- setUpNightMode();
+ if (mCurrentUser != UserHandle.USER_NULL) {
+ if (mUserSetupObserver != null) {
+ cr.unregisterContentObserver(mUserSetupObserver);
+ mUserSetupObserver = null;
+ } else if (mBootCompleted) {
+ tearDown();
+ }
+ }
+
+ mCurrentUser = userHandle;
+
+ if (mCurrentUser != UserHandle.USER_NULL) {
+ if (!isUserSetupCompleted(cr, mCurrentUser)) {
+ mUserSetupObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (isUserSetupCompleted(cr, mCurrentUser)) {
+ cr.unregisterContentObserver(this);
+ mUserSetupObserver = null;
+
+ if (mBootCompleted) {
+ setUp();
+ }
+ }
+ }
+ };
+ cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
+ false /* notifyForDescendents */, mUserSetupObserver, mCurrentUser);
+ } else if (mBootCompleted) {
+ setUp();
}
}
}
- private void setUpNightMode() {
+ private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
+ return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
+ }
+
+ private void setUp() {
// Create a new controller for the current user and start listening for changes.
mController = new NightDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
@@ -140,8 +170,11 @@
}
}
- private void tearDownNightMode() {
- mController.setListener(null);
+ private void tearDown() {
+ if (mController != null) {
+ mController.setListener(null);
+ mController = null;
+ }
if (mAutoMode != null) {
mAutoMode.onStop();
@@ -149,7 +182,6 @@
}
mIsActivated = null;
- mController = null;
}
@Override
@@ -324,13 +356,11 @@
private class TwilightAutoMode extends AutoMode implements TwilightListener {
private final TwilightManager mTwilightManager;
- private final Handler mHandler;
private boolean mIsNight;
public TwilightAutoMode() {
mTwilightManager = getLocalService(TwilightManager.class);
- mHandler = new Handler(Looper.getMainLooper());
}
private void updateActivated() {
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 552c990..0947554 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -486,6 +486,7 @@
+ ":[" + job.getService()
+ ",jId=" + job.getId()
+ ",u" + getUserId()
+ + ",suid=" + getSourceUid()
+ ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
+ "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
+ ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index b94d0f0..3c18198 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -34,6 +34,7 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.ShortcutOperation;
+import com.android.server.pm.ShortcutService.Stats;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -437,8 +438,6 @@
* locale changes.
*/
public int getApiCallCount() {
- mShortcutUser.resetThrottlingIfNeeded();
-
final ShortcutService s = mShortcutUser.mService;
// Reset the counter if:
@@ -598,7 +597,37 @@
}
/**
- * Called when the package is updated or added.
+ * @return false if any of the target activities are no longer enabled.
+ */
+ private boolean areAllActivitiesStillEnabled() {
+ if (mShortcuts.size() == 0) {
+ return true;
+ }
+ final ShortcutService s = mShortcutUser.mService;
+
+ // Normally the number of target activities is 1 or so, so no need to use a complex
+ // structure like a set.
+ final ArrayList<ComponentName> checked = new ArrayList<>(4);
+
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.valueAt(i);
+ final ComponentName activity = si.getActivity();
+
+ if (checked.contains(activity)) {
+ continue; // Already checked.
+ }
+ checked.add(activity);
+
+ if (!s.injectIsActivityEnabledAndExported(activity, getOwnerUserId())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when the package may be added or updated, or its activities may be disabled, and
+ * if so, rescan the package and do the necessary stuff.
*
* Add case:
* - Publish manifest shortcuts.
@@ -606,23 +635,35 @@
* Update case:
* - Re-publish manifest shortcuts.
* - If there are shortcuts with resources (icons or strings), update their timestamps.
+ * - Disable shortcuts whose target activities are disabled.
*
* @return TRUE if any shortcuts have been changed.
*/
- public boolean handlePackageAddedOrUpdated(boolean isNewApp, boolean forceRescan) {
- final PackageInfo pi = mShortcutUser.mService.getPackageInfo(
- getPackageName(), getPackageUserId());
- if (pi == null) {
- return false; // Shouldn't happen.
- }
+ public boolean rescanPackageIfNeeded(boolean isNewApp, boolean forceRescan) {
+ final ShortcutService s = mShortcutUser.mService;
+ final long start = s.injectElapsedRealtime();
- if (!isNewApp && !forceRescan) {
- // Make sure the version code or last update time has changed.
- // Otherwise, nothing to do.
- if (getPackageInfo().getVersionCode() >= pi.versionCode
- && getPackageInfo().getLastUpdateTime() >= pi.lastUpdateTime) {
- return false;
+ final PackageInfo pi;
+ try {
+ pi = mShortcutUser.mService.getPackageInfo(
+ getPackageName(), getPackageUserId());
+ if (pi == null) {
+ return false; // Shouldn't happen.
}
+
+ if (!isNewApp && !forceRescan) {
+ // Return if the package hasn't changed, ie:
+ // - version code hasn't change
+ // - lastUpdateTime hasn't change
+ // - all target activities are still enabled.
+ if ((getPackageInfo().getVersionCode() >= pi.versionCode)
+ && (getPackageInfo().getLastUpdateTime() >= pi.lastUpdateTime)
+ && areAllActivitiesStillEnabled()) {
+ return false;
+ }
+ }
+ } finally {
+ s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
}
// Now prepare to publish manifest shortcuts.
@@ -654,8 +695,6 @@
getPackageInfo().updateVersionInfo(pi);
- final ShortcutService s = mShortcutUser.mService;
-
boolean changed = false;
// For existing shortcuts, update timestamps if they have any resources.
@@ -1001,7 +1040,7 @@
}
}
if (changed) {
- s.scheduleSaveUser(getPackageUserId());
+ s.packageShortcutsChanged(getPackageName(), getPackageUserId());
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 757dd19..26b52e9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -48,6 +48,10 @@
mPackageInfo = Preconditions.checkNotNull(packageInfo);
}
+ public ShortcutUser getUser() {
+ return mShortcutUser;
+ }
+
/**
* ID of the user who actually has this package running on. For {@link ShortcutPackage},
* this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 730217d..4286cd9 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -24,9 +24,11 @@
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -49,10 +51,12 @@
import android.graphics.Canvas;
import android.graphics.RectF;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.LocaleList;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -116,15 +120,11 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* TODO:
- * - Deal with the async nature of PACKAGE_ADD. Basically when a publisher does anything after
- * it's upgraded, the manager should make sure the upgrade process has been executed.
- *
* - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
* -> But TypedValue.applyDimension() doesn't differentiate x and y..?
*
@@ -179,7 +179,6 @@
private static final String TAG_ROOT = "root";
private static final String TAG_LAST_RESET_TIME = "last_reset_time";
- private static final String TAG_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale_seq_no";
private static final String ATTR_VALUE = "value";
@@ -292,16 +291,6 @@
@GuardedBy("mLock")
private List<Integer> mDirtyUserIds = new ArrayList<>();
- /**
- * A counter that increments every time the system locale changes. We keep track of it to
- * reset
- * throttling counters on the first call from each package after the last locale change.
- *
- * We need this mechanism because we can't do much in the locale change callback, which is
- * {@link ShortcutServiceInternal#onSystemLocaleChangedNoLock()}.
- */
- private final AtomicLong mLocaleChangeSequenceNumber = new AtomicLong();
-
private final AtomicBoolean mBootCompleted = new AtomicBoolean();
private static final int PACKAGE_MATCH_FLAGS =
@@ -326,8 +315,9 @@
int GET_LAUNCHER_ACTIVITY = 11;
int CHECK_LAUNCHER_ACTIVITY = 12;
int IS_ACTIVITY_ENABLED = 13;
+ int PACKAGE_UPDATE_CHECK = 14;
- int COUNT = IS_ACTIVITY_ENABLED + 1;
+ int COUNT = PACKAGE_UPDATE_CHECK + 1;
}
final Object mStatLock = new Object();
@@ -381,7 +371,25 @@
return; // Don't do anything further. For unit tests only.
}
- mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
+ // Register receivers.
+
+ // We need to set a priority, so let's just not use PackageMonitor for now.
+ // TODO Refactor PackageMonitor to support priorities.
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageFilter.addDataScheme("package");
+ packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
+ packageFilter, null, mHandler);
+
+ final IntentFilter localeFilter = new IntentFilter();
+ localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ localeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
+ localeFilter, null, mHandler);
injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
| ActivityManager.UID_OBSERVER_GONE);
@@ -394,8 +402,9 @@
}
}
- public long getLocaleChangeSequenceNumber() {
- return mLocaleChangeSequenceNumber.get();
+ public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
+ // TODO This should get the per-user locale. b/30123329 b/30119489
+ return LocaleList.getDefault().toLanguageTags();
}
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@@ -504,8 +513,11 @@
Slog.d(TAG, "handleUnlockUser: user=" + userId);
}
synchronized (mLock) {
- // Preload
- getUserShortcutsLocked(userId);
+ // Preload the user's shortcuts.
+ // Also see if the locale has changed.
+ // Note as of nyc, the locale is per-user, so the locale shouldn't change
+ // when the user is locked. However due to b/30119489 it still happens.
+ getUserShortcutsLocked(userId).detectLocaleChange();
checkPackageChanges(userId);
}
@@ -751,8 +763,6 @@
// Body.
writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
- writeTagValue(out, TAG_LOCALE_CHANGE_SEQUENCE_NUMBER,
- mLocaleChangeSequenceNumber.get());
// Epilogue.
out.endTag(null, TAG_ROOT);
@@ -797,9 +807,6 @@
case TAG_LAST_RESET_TIME:
mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
break;
- case TAG_LOCALE_CHANGE_SEQUENCE_NUMBER:
- mLocaleChangeSequenceNumber.set(parseLongAttribute(parser, ATTR_VALUE));
- break;
default:
Slog.e(TAG, "Invalid tag: " + tag);
break;
@@ -1501,6 +1508,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1550,6 +1558,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1628,6 +1637,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
@@ -1675,6 +1685,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1702,6 +1713,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1722,6 +1734,7 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
@@ -1743,7 +1756,9 @@
verifyCaller(packageName, userId);
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts();
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ ps.deleteAllDynamicShortcuts();
}
packageShortcutsChanged(packageName, userId);
@@ -1788,7 +1803,9 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
- getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags);
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ ps.findAll(ret, query, cloneFlags);
return new ParceledListSlice<>(ret);
}
@@ -1806,8 +1823,9 @@
verifyCaller(packageName, userId);
synchronized (mLock) {
- return mMaxUpdatesPerInterval
- - getPackageShortcutsLocked(packageName, userId).getApiCallCount();
+ final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+ return mMaxUpdatesPerInterval - ps.getApiCallCount();
}
}
@@ -1842,6 +1860,8 @@
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+ ps.getUser().onCalledByPublisher(packageName);
+
if (ps.findShortcutById(shortcutId) == null) {
Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
packageName, shortcutId));
@@ -2039,7 +2059,7 @@
if (appStillExists && (packageUserId == owningUserId)) {
// This will do the notification and save when needed, so do it after the above
// notifyListeners.
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
}
if (!wasUserLoaded) {
@@ -2282,36 +2302,19 @@
@NonNull String callingPackage) {
return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
}
+ }
- /**
- * Called by AM when the system locale changes *within the AM lock. ABSOLUTELY do not take
- * any locks in this method.
- */
+ final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
- public void onSystemLocaleChangedNoLock() {
- // DO NOT HOLD ANY LOCKS HERE.
-
- // We want to reset throttling for all packages for all users. But we can't just do so
- // here because:
- // - We can't load/save users that are locked.
- // - Even for loaded users, resetting the counters would require us to hold mLock.
- //
- // So we use a "pull" model instead. In here, we just increment the "locale change
- // sequence number". Each ShortcutUser has the "last known locale change sequence".
- //
- // This allows ShortcutUser's to detect the system locale change, so they can reset
- // counters.
-
- // Ignore all callback during system boot.
- if (mBootCompleted.get()) {
- mLocaleChangeSequenceNumber.incrementAndGet();
- if (DEBUG) {
- Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get());
- }
- injectPostToHandler(() -> handleLocaleChanged());
+ public void onReceive(Context context, Intent intent) {
+ if (!mBootCompleted.get()) {
+ return; // Boot not completed, ignore the broadcast.
+ }
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ handleLocaleChanged();
}
}
- }
+ };
void handleLocaleChanged() {
if (DEBUG) {
@@ -2321,7 +2324,7 @@
final long token = injectClearCallingIdentity();
try {
- forEachLoadedUserLocked(u -> u.forAllPackages(p -> p.resolveResourceStrings()));
+ forEachLoadedUserLocked(user -> user.detectLocaleChange());
} finally {
injectRestoreCallingIdentity(token);
}
@@ -2331,53 +2334,65 @@
* Package event callbacks.
*/
@VisibleForTesting
- final PackageMonitor mPackageMonitor = new PackageMonitor() {
-
- private boolean isUserUnlocked() {
- return mUserManager.isUserUnlocked(getChangingUserId());
- }
-
+ final BroadcastReceiver mPackageMonitor = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // clearCallingIdentity is not needed normally, but need to do it for the unit test.
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
+ return;
+ }
+
+ final String action = intent.getAction();
+
+ // This is normally called on Handler, so clearCallingIdentity() isn't needed,
+ // but we still check it in unit tests.
final long token = injectClearCallingIdentity();
try {
- super.onReceive(context, intent);
+
+ if (!mUserManager.isUserUnlocked(userId)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring package broadcast " + action
+ + " for locked/stopped user " + userId);
+ }
+ return;
+ }
+
+ final Uri intentUri = intent.getData();
+ final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
+ : null;
+ if (packageName == null) {
+ Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
+ return;
+ }
+
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ switch (action) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ if (replacing) {
+ handlePackageUpdateFinished(packageName, userId);
+ } else {
+ handlePackageAdded(packageName, userId);
+ }
+ break;
+ case Intent.ACTION_PACKAGE_REMOVED:
+ if (!replacing) {
+ handlePackageRemoved(packageName, userId);
+ }
+ break;
+ case Intent.ACTION_PACKAGE_CHANGED:
+ handlePackageChanged(packageName, userId);
+
+ break;
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ handlePackageDataCleared(packageName, userId);
+ break;
+ }
} finally {
injectRestoreCallingIdentity(token);
}
}
-
- @Override
- public void onPackageAdded(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageAdded(packageName, getChangingUserId());
- }
-
- @Override
- public void onPackageUpdateFinished(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageUpdateFinished(packageName, getChangingUserId());
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageRemoved(packageName, getChangingUserId());
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageDataCleared(packageName, getChangingUserId());
- }
-
- @Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- if (!isUserUnlocked()) return false;
- handlePackageChanged(packageName, getChangingUserId());
- return false; // We don't need to receive onSomePackagesChanged(), so just false.
- }
};
/**
@@ -2427,7 +2442,7 @@
// Then for each installed app, publish manifest shortcuts when needed.
forUpdatedPackages(ownerUserId, user.getLastAppScanTime(), ai -> {
- user.handlePackageAddedOrUpdated(ai.packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(ai.packageName, /* forceRescan=*/ false);
});
// Write the time just before the scan, because there may be apps that have just
@@ -2448,7 +2463,7 @@
synchronized (mLock) {
final ShortcutUser user = getUserShortcutsLocked(userId);
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ false);
}
verifyStates();
}
@@ -2463,7 +2478,7 @@
user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
if (isPackageInstalled(packageName, userId)) {
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ false);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ false);
}
}
verifyStates();
@@ -2499,7 +2514,7 @@
synchronized (mLock) {
final ShortcutUser user = getUserShortcutsLocked(packageUserId);
- user.handlePackageAddedOrUpdated(packageName, /* forceRescan=*/ true);
+ user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
}
verifyStates();
@@ -2975,10 +2990,6 @@
pw.print("] ");
pw.print(formatTime(next));
- pw.print(" Locale change seq#: ");
- pw.print(mLocaleChangeSequenceNumber.get());
- pw.println();
-
pw.print(" Config:");
pw.print(" Max icon dim: ");
pw.println(mMaxIconDimension);
@@ -3014,6 +3025,7 @@
dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
+ dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
}
pw.println();
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 7ea89c9..9649641 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -19,6 +19,8 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
+import android.content.pm.ShortcutManager;
+import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.Slog;
@@ -51,7 +53,7 @@
private static final String TAG_LAUNCHER = "launcher";
private static final String ATTR_VALUE = "value";
- private static final String ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale-seq-no";
+ private static final String ATTR_KNOWN_LOCALES = "locales";
private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time";
static final class PackageWithUser {
@@ -104,7 +106,7 @@
/** Default launcher that can access the launcher apps APIs. */
private ComponentName mDefaultLauncherComponent;
- private long mKnownLocaleChangeSequenceNumber;
+ private String mKnownLocales;
private long mLastAppScanTime;
@@ -225,29 +227,62 @@
}
/**
- * Reset all throttling counters for all packages, if there has been a system locale change.
+ * Must be called at any entry points on {@link ShortcutManager} APIs to make sure the
+ * information on the package is up-to-date.
+ *
+ * We use broadcasts to handle locale changes and package changes, but because broadcasts
+ * are asynchronous, there's a chance a publisher calls getXxxShortcuts() after a certain event
+ * (e.g. system locale change) but shortcut manager hasn't finished processing the broadcast.
+ *
+ * So we call this method at all entry points from publishers to make sure we update all
+ * relevant information.
+ *
+ * Similar inconsistencies can happen when the launcher fetches shortcut information, but
+ * that's a less of an issue because for the launcher we report shortcut changes with
+ * callbacks.
*/
- public void resetThrottlingIfNeeded() {
- final long currentNo = mService.getLocaleChangeSequenceNumber();
- if (mKnownLocaleChangeSequenceNumber < currentNo) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "LocaleChange detected for user " + mUserId);
- }
-
- mKnownLocaleChangeSequenceNumber = currentNo;
-
- forAllPackages(p -> p.resetRateLimiting());
-
- mService.scheduleSaveUser(mUserId);
- }
+ public void onCalledByPublisher(@NonNull String packageName) {
+ detectLocaleChange();
+ rescanPackageIfNeeded(packageName, /*forceRescan=*/ false);
}
- public void handlePackageAddedOrUpdated(@NonNull String packageName, boolean forceRescan) {
+ private String getKnownLocales() {
+ if (TextUtils.isEmpty(mKnownLocales)) {
+ mKnownLocales = mService.injectGetLocaleTagsForUser(mUserId);
+ mService.scheduleSaveUser(mUserId);
+ }
+ return mKnownLocales;
+ }
+
+ /**
+ * Check to see if the system locale has changed, and if so, reset throttling
+ * and update resource strings.
+ */
+ public void detectLocaleChange() {
+ final String currentLocales = mService.injectGetLocaleTagsForUser(mUserId);
+ if (getKnownLocales().equals(currentLocales)) {
+ return;
+ }
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, "Locale changed from " + currentLocales + " to " + mKnownLocales
+ + " for user " + mUserId);
+ }
+ mKnownLocales = currentLocales;
+
+ forAllPackages(pkg -> {
+ pkg.resetRateLimiting();
+ pkg.resolveResourceStrings();
+ });
+
+ mService.scheduleSaveUser(mUserId);
+ }
+
+ public void rescanPackageIfNeeded(@NonNull String packageName, boolean forceRescan) {
final boolean isNewApp = !mPackages.containsKey(packageName);
final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
- if (!shortcutPackage.handlePackageAddedOrUpdated(isNewApp, forceRescan)) {
+ if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
if (isNewApp) {
mPackages.remove(packageName);
}
@@ -265,8 +300,7 @@
throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
- ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER,
- mKnownLocaleChangeSequenceNumber);
+ ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
mLastAppScanTime);
@@ -307,8 +341,8 @@
boolean fromBackup) throws IOException, XmlPullParserException {
final ShortcutUser ret = new ShortcutUser(s, userId);
- ret.mKnownLocaleChangeSequenceNumber = ShortcutService.parseLongAttribute(parser,
- ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER);
+ ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
+ ATTR_KNOWN_LOCALES);
// If lastAppScanTime is in the future, that means the clock went backwards.
// Just scan all apps again.
@@ -377,8 +411,8 @@
pw.print(prefix);
pw.print("User: ");
pw.print(mUserId);
- pw.print(" Known locale seq#: ");
- pw.print(mKnownLocaleChangeSequenceNumber);
+ pw.print(" Known locales: ");
+ pw.print(mKnownLocales);
pw.print(" Last app scan: [");
pw.print(mLastAppScanTime);
pw.print("] ");
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 57f784a..0f812ac 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -180,6 +180,7 @@
private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+ private static final int IPV4_ANY_HOST_ADDRESS = 0;
private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
@@ -201,12 +202,14 @@
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
- private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+ private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
+ private static final short ARP_OPCODE_REQUEST = 1;
+ private static final short ARP_OPCODE_REPLY = 2;
+ private static final byte[] ARP_IPV4_HEADER = new byte[]{
0, 1, // Hardware type: Ethernet (1)
8, 0, // Protocol type: IP (0x0800)
6, // Hardware size: 6
4, // Protocol size: 4
- 0, 1 // Opcode: request (1)
};
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
@@ -667,23 +670,48 @@
private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
// Here's a basic summary of what the ARP filter program does:
//
- // if interface has IPv4 address:
- // if it's not an ARP IPv4 request:
- // pass
- // if it's not a request for our IPv4 address:
- // drop
+ // if not ARP IPv4
+ // pass
+ // if not ARP IPv4 reply or request
+ // pass
+ // if unicast ARP reply
+ // pass
+ // if interface has no IPv4 address
+ // if target ip is 0.0.0.0
+ // drop
+ // else
+ // if target ip is not the interface ip
+ // drop
// pass
- if (mIPv4Address != null) {
- // if it's not an ARP IPv4 request, pass
- gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_REQUEST_HEADER, gen.PASS_LABEL);
- // if it's not a request for our IPv4 address, drop
+ final String checkTargetIPv4 = "checkTargetIPv4";
+
+ // Pass if not ARP IPv4.
+ gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL);
+
+ // Pass if unknown ARP opcode.
+ gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
+ gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
+ gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL);
+
+ // Pass if unicast reply.
+ gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
+
+ // Either a unicast request, a unicast reply, or a broadcast reply.
+ gen.defineLabel(checkTargetIPv4);
+ if (mIPv4Address == null) {
+ // When there is no IPv4 address, drop GARP replies (b/29404209).
+ gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+ gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL);
+ } else {
+ // When there is an IPv4 address, drop unicast/broadcast requests
+ // and broadcast replies with a different target IPv4 address.
gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
}
- // Otherwise, pass
gen.addJump(gen.PASS_LABEL);
}
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index 815133a..bd76118 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -580,7 +580,7 @@
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
IpConnectivityLog log) throws Exception {
- super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
+ super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
ipManagerCallback, multicastFilter, log);
}
@@ -618,6 +618,7 @@
}
private static final int ETH_HEADER_LEN = 14;
+ private static final int ETH_DEST_ADDR_OFFSET = 0;
private static final int ETH_ETHERTYPE_OFFSET = 12;
private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
@@ -676,9 +677,18 @@
4, // Protocol size: 4
0, 1 // Opcode: request (1)
};
+ private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
+ 0, 1, // Hardware type: Ethernet (1)
+ 8, 0, // Protocol type: IP (0x0800)
+ 6, // Hardware size: 6
+ 4, // Protocol size: 4
+ 0, 2 // Opcode: reply (2)
+ };
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
+ private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
+ private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
@LargeTest
public void testApfFilterIPv4() throws Exception {
@@ -801,51 +811,81 @@
apfFilter.shutdown();
}
- private void verifyArpFilter(MockIpManagerCallback ipManagerCallback, ApfFilter apfFilter,
- LinkProperties linkProperties, int filterResult) {
- ipManagerCallback.resetApfProgramWait();
- apfFilter.setLinkProperties(linkProperties);
- byte[] program = ipManagerCallback.getApfProgram();
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_HEADER_OFFSET);
- packet.put(ARP_IPV4_REQUEST_HEADER);
- assertVerdict(filterResult, program, packet.array(), 0);
- packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
- packet.put(MOCK_IPV4_ADDR);
- assertPass(program, packet.array(), 0);
+ private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
+ cb.resetApfProgramWait();
+ filter.setLinkProperties(lp);
+ return cb.getApfProgram();
+ }
+
+ private void verifyArpFilter(byte[] program, int filterResult) {
+ // Verify ARP request packet
+ assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
+ assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
+ assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
+
+ // Verify unicast ARP reply packet is always accepted.
+ assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
+ assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
+ assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
+
+ // Verify GARP reply packets are always filtered
+ assertDrop(program, garpReply(), 0);
}
@LargeTest
public void testApfFilterArp() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
- byte[] program = ipManagerCallback.getApfProgram();
- // Verify initially ARP filter is off
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_HEADER_OFFSET);
- packet.put(ARP_IPV4_REQUEST_HEADER);
- assertPass(program, packet.array(), 0);
- packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
- packet.put(MOCK_IPV4_ADDR);
- assertPass(program, packet.array(), 0);
+ // Verify initially ARP request filter is off, and GARP filter is on.
+ verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
// Inform ApfFilter of our address and verify ARP filtering is on
+ LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
LinkProperties lp = new LinkProperties();
- assertTrue(lp.addLinkAddress(
- new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24)));
- verifyArpFilter(ipManagerCallback, apfFilter, lp, DROP);
+ assertTrue(lp.addLinkAddress(linkAddress));
+ verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
// Inform ApfFilter of loss of IP and verify ARP filtering is off
- verifyArpFilter(ipManagerCallback, apfFilter, new LinkProperties(), PASS);
+ verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
apfFilter.shutdown();
}
+ private static byte[] arpRequestBroadcast(byte[] tip) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ETH_DEST_ADDR_OFFSET);
+ packet.put(ETH_BROADCAST_MAC_ADDRESS);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REQUEST_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(tip);
+ return packet.array();
+ }
+
+ private static byte[] arpReplyUnicast(byte[] tip) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REPLY_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(tip);
+ return packet.array();
+ }
+
+ private static byte[] garpReply() {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+ packet.position(ETH_DEST_ADDR_OFFSET);
+ packet.put(ETH_BROADCAST_MAC_ADDRESS);
+ packet.position(ARP_HEADER_OFFSET);
+ packet.put(ARP_IPV4_REPLY_HEADER);
+ packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
+ packet.put(IPV4_ANY_HOST_ADDR);
+ return packet.array();
+ }
+
// Verify that the last program pushed to the IpManager.Callback properly filters the
// given packet for the given lifetime.
private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1be57bc..2652b8f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -110,13 +110,14 @@
public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected static final String TAG = "ShortcutManagerTest";
+ protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
/**
* Whether to enable dump or not. Should be only true when debugging to avoid bugs where
* dump affecting the behavior.
*/
- protected static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
-
- protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+ protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true
+ || DUMP_IN_TEARDOWN || ShortcutService.DEBUG;
protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
@@ -154,6 +155,11 @@
// ignore.
return null;
}
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ // ignore.
+ }
}
/** Context used in the client side */
@@ -212,6 +218,11 @@
}
@Override
+ public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
+ return mInjectedLocale.toLanguageTag();
+ }
+
+ @Override
boolean injectShouldPerformVerification() {
return true; // Always verify during unit tests.
}
@@ -715,11 +726,6 @@
// Start the service.
initService();
setCaller(CALLING_PACKAGE_1);
-
- // In order to complicate the situation, we set mLocaleChangeSequenceNumber to 1 by
- // calling this. Running test with mLocaleChangeSequenceNumber == 0 might make us miss
- // some edge cases.
- mInternal.onSystemLocaleChangedNoLock();
}
/**
@@ -837,12 +843,6 @@
// Send boot sequence events.
mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
- // Make sure a call to onSystemLocaleChangedNoLock() before PHASE_BOOT_COMPLETED will be
- // ignored.
- final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
- mInternal.onSystemLocaleChangedNoLock();
- assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber());
-
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index bf6c2ff..d563185 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -5730,21 +5730,24 @@
mRunningUsers.put(USER_10, false);
mUnlockedUsers.put(USER_10, false);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertEmpty(mManager.getManifestShortcuts());
- assertEmpty(mManager.getPinnedShortcuts());
+ // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
+ // update check.
+ // So look the internal data directly using getCallerShortcuts().
+ assertEmpty(getCallerShortcuts());
});
// Try again, but the user is locked, so still ignored.
mRunningUsers.put(USER_10, true);
-
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertEmpty(mManager.getManifestShortcuts());
- assertEmpty(mManager.getPinnedShortcuts());
+ // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
+ // update check.
+ // So look the internal data directly using getCallerShortcuts().
+ assertEmpty(getCallerShortcuts());
});
// Unlock the user, now it should work.
@@ -6108,7 +6111,7 @@
});
}
- public void testManifestShortcuts_localeChange() {
+ public void testManifestShortcuts_localeChange() throws InterruptedException {
mService.handleUnlockUser(USER_0);
// Package 1 updated, which has one valid manifest shortcut and one invalid.
@@ -6164,8 +6167,15 @@
mInjectedCurrentTimeMillis++;
+ // Change the locale and send the broadcast, make sure the launcher gets a callback too.
mInjectedLocale = Locale.JAPANESE;
- mInternal.onSystemLocaleChangedNoLock();
+
+ setCaller(LAUNCHER_1, USER_0);
+
+ assertForLauncherCallback(mLauncherApps, () -> {
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+ }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
+ .haveIds("ms1", "ms2", "s1");
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
// check first shortcut.
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index d546092..bd413be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -47,6 +47,8 @@
import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants;
+import java.util.Locale;
+
/**
* Tests for ShortcutService and ShortcutManager.
*
@@ -1357,13 +1359,12 @@
mService.saveDirtyInfo();
initService();
- final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
-
- mInternal.onSystemLocaleChangedNoLock();
- assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+ mInjectedLocale = Locale.CHINA;
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
// Note at this point only user-0 is loaded, and the counters are reset for this user,
- // but it will work for other users too, because we persist when
+ // but it will work for other users too because we check the locale change at any
+ // API entry point.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(3, mManager.getRemainingCallCount());
@@ -1384,11 +1385,28 @@
assertEquals(3, mManager.getRemainingCallCount());
});
+ // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually
+ // changed, we don't reset throttling.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.updateShortcuts(list());
+ assertEquals(2, mManager.getRemainingCallCount());
+ });
+
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
+ });
+
mService.saveDirtyInfo();
initService();
- // Make sure the counter is persisted.
- assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+ // The locale should be persisted, so it still shouldn't reset throttling.
+ mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
+ });
}
public void testThrottling_foreground() throws Exception {
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index f89c4e4..2f64ad7 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -973,6 +973,8 @@
waitOnMainThread();
+ launcherApps.unregisterCallback(asserter.getMockCallback());
+
return asserter;
}
}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index ea36e2c..2956d87 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -256,23 +256,33 @@
def check_emoji_coverage(all_emoji, equivalent_emoji):
+ emoji_font = get_emoji_font()
+ check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
+
+
+def get_emoji_font():
emoji_fonts = [
record.font for record in _fallback_chain
if 'Zsye' in record.scripts]
assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
- emoji_font = emoji_fonts[0]
- coverage = get_emoji_map(emoji_font)
+ return emoji_fonts[0]
+
+def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
+ coverage = get_emoji_map(emoji_font)
for sequence in all_emoji:
assert sequence in coverage, (
'%s is not supported in the emoji font.' % printable(sequence))
+ # disable temporarily - we cover more than this
+ """
for sequence in coverage:
if sequence in {0x0000, 0x000D, 0x0020}:
# The font needs to support a few extra characters, which is OK
continue
assert sequence in all_emoji, (
'Emoji font should not support %s.' % printable(sequence))
+ """
for first, second in sorted(equivalent_emoji.items()):
assert coverage[first] == coverage[second], (
@@ -280,6 +290,8 @@
printable(first),
printable(second)))
+ # disable temporarily - some equivalent sequences we don't even know about
+ """
for glyph in set(coverage.values()):
maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
if len(maps_to_glyph) > 1:
@@ -295,7 +307,7 @@
'The sequences %s should not result in the same glyph %s' % (
printable(equivalent_seqs),
glyph))
-
+ """
def check_emoji_defaults(default_emoji):
missing_text_chars = _emoji_properties['Emoji'] - default_emoji
@@ -427,6 +439,11 @@
_emoji_sequences = dict(
(t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t))
+ # add in UN flag
+ UN_seq = flag_sequence('UN')
+ _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
+
+
def flag_sequence(territory_code):
return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
@@ -483,6 +500,11 @@
(0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F466): 0x1F46A,
}
+
+def is_fitzpatrick_modifier(cp):
+ return 0x1f3fb <= cp <= 0x1f3ff
+
+
def compute_expected_emoji():
equivalent_emoji = {}
sequence_pieces = set()
@@ -500,7 +522,15 @@
sequence_pieces.update(sequence)
# Add reverse of all emoji ZWJ sequences, which are added to the fonts
# as a workaround to get the sequences work in RTL text.
- reversed_seq = tuple(reversed(sequence))
+ reversed_seq = list(reversed(sequence))
+ # if there are fitzpatrick modifiers in the sequence, keep them after
+ # the emoji they modify
+ for i in xrange(1, len(reversed_seq)):
+ if is_fitzpatrick_modifier(reversed_seq[i - 1]):
+ tmp = reversed_seq[i]
+ reversed_seq[i] = reversed_seq[i-1]
+ reversed_seq[i-1] = tmp
+ reversed_seq = tuple(reversed_seq)
all_sequences.add(reversed_seq)
equivalent_emoji[reversed_seq] = sequence
@@ -536,8 +566,8 @@
def main():
- target_out = sys.argv[1]
global _fonts_dir
+ target_out = sys.argv[1]
_fonts_dir = path.join(target_out, 'fonts')
fonts_xml_path = path.join(target_out, 'etc', 'fonts.xml')