Merge "Add test for ascent and descent of serif and mono fonts"
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 3ab60f8..adfdfba 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -409,24 +409,26 @@
if (alias == null) {
throw new NullPointerException("alias == null");
}
- KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
- try {
- final IKeyChainService keyChainService = keyChainConnection.getService();
- final String keyId = keyChainService.requestPrivateKey(alias);
- if (keyId == null) {
- return null;
- }
- return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
- KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
+
+ final String keyId;
+ try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) {
+ keyId = keyChainConnection.getService().requestPrivateKey(alias);
} catch (RemoteException e) {
throw new KeyChainException(e);
} catch (RuntimeException e) {
// only certain RuntimeExceptions can be propagated across the IKeyChainService call
throw new KeyChainException(e);
- } catch (UnrecoverableKeyException e) {
- throw new KeyChainException(e);
- } finally {
- keyChainConnection.close();
+ }
+
+ if (keyId == null) {
+ return null;
+ } else {
+ try {
+ return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
+ } catch (RuntimeException | UnrecoverableKeyException e) {
+ throw new KeyChainException(e);
+ }
}
}
@@ -453,16 +455,25 @@
if (alias == null) {
throw new NullPointerException("alias == null");
}
- KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
- try {
- IKeyChainService keyChainService = keyChainConnection.getService();
- final byte[] certificateBytes = keyChainService.getCertificate(alias);
+ final byte[] certificateBytes;
+ final byte[] certChainBytes;
+ try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) {
+ IKeyChainService keyChainService = keyChainConnection.getService();
+ certificateBytes = keyChainService.getCertificate(alias);
if (certificateBytes == null) {
return null;
}
+ certChainBytes = keyChainService.getCaCertificates(alias);
+ } catch (RemoteException e) {
+ throw new KeyChainException(e);
+ } catch (RuntimeException e) {
+ // only certain RuntimeExceptions can be propagated across the IKeyChainService call
+ throw new KeyChainException(e);
+ }
+
+ try {
X509Certificate leafCert = toCertificate(certificateBytes);
- final byte[] certChainBytes = keyChainService.getCaCertificates(alias);
// If the keypair is installed with a certificate chain by either
// DevicePolicyManager.installKeyPair or CertInstaller, return that chain.
if (certChainBytes != null && certChainBytes.length != 0) {
@@ -486,15 +497,8 @@
List<X509Certificate> chain = store.getCertificateChain(leafCert);
return chain.toArray(new X509Certificate[chain.size()]);
}
- } catch (CertificateException e) {
+ } catch (CertificateException | RuntimeException e) {
throw new KeyChainException(e);
- } catch (RemoteException e) {
- throw new KeyChainException(e);
- } catch (RuntimeException e) {
- // only certain RuntimeExceptions can be propagated across the IKeyChainService call
- throw new KeyChainException(e);
- } finally {
- keyChainConnection.close();
}
}
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 5f4c9c5..2eaf187 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -80,8 +80,6 @@
static Vector2 centroid2d(const Vector2* poly, int polyLength);
- static bool isClockwise(const Vector2* polygon, int len);
-
static Vector2 calculateNormal(const Vector2& p1, const Vector2& p2);
static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 760d814..e2ee5bf 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -302,21 +302,6 @@
}
/**
- * Make the polygon turn clockwise.
- *
- * @param polygon the polygon as a Vector2 array.
- * @param len the number of points of the polygon
- */
-void SpotShadow::makeClockwise(Vector2* polygon, int len) {
- if (polygon == nullptr || len == 0) {
- return;
- }
- if (!ShadowTessellator::isClockwise(polygon, len)) {
- reverse(polygon, len);
- }
-}
-
-/**
* Reverse the polygon
*
* @param polygon the polygon as a Vector2 array
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 62a7e5d..6108bb6 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -54,7 +54,6 @@
static void quicksortX(Vector2* points, int low, int high);
static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len);
- static void makeClockwise(Vector2* polygon, int len);
static void reverse(Vector2* polygon, int len);
static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3174c70..64dea57 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -630,7 +630,11 @@
MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
- AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
+ if (isPlatformTelevision()) {
+ AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume / 4;
+ } else {
+ AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
+ }
}
sSoundEffectVolumeDb = context.getResources().getInteger(
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 872ebe8..1cf5097 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -16,13 +16,18 @@
package com.android.server.am;
+import android.app.IUserSwitchObserver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.UserInfo;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.os.UserManagerInternal;
import android.test.AndroidTestCase;
@@ -35,16 +40,30 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerService.CONTINUE_USER_SWITCH_MSG;
+import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
+import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
+import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
+import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
+import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
public class UserControllerTest extends AndroidTestCase {
+ private static final int TEST_USER_ID = 10;
private static String TAG = UserControllerTest.class.getSimpleName();
private UserController mUserController;
private TestInjector mInjector;
@@ -54,7 +73,7 @@
super.setUp();
mInjector = new TestInjector(getContext());
mUserController = new UserController(mInjector);
- setUpUser(10, 0);
+ setUpUser(TEST_USER_ID, 0);
}
@Override
@@ -65,13 +84,100 @@
}
public void testStartUser() throws RemoteException {
- mUserController.startUser(10, true);
-
+ mUserController.startUser(TEST_USER_ID, true);
Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
List<String> expectedActions = Arrays.asList(Intent.ACTION_USER_STARTED,
Intent.ACTION_USER_SWITCHED, Intent.ACTION_USER_STARTING);
assertEquals(expectedActions, getActions(mInjector.sentIntents));
+ Set<Integer> expectedCodes = new HashSet<>(
+ Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
+ SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
+ Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
+ assertEquals("Unexpected message sent", expectedCodes, actualCodes);
+ Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
+ assertNotNull(reportMsg);
+ UserState userState = (UserState) reportMsg.obj;
+ assertNotNull(userState);
+ assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
+ assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
+ assertEquals("Unexpected old user id", 0, reportMsg.arg1);
+ assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
+ }
+
+ public void testDispatchUserSwitch() throws RemoteException {
+ // Prepare mock observer and register it
+ IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
+ when(observer.asBinder()).thenReturn(new Binder());
+ doAnswer(invocation -> {
+ IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
+ callback.sendResult(null);
+ return null;
+ }).when(observer).onUserSwitching(anyInt(), any());
+ mUserController.registerUserSwitchObserver(observer, "mock");
+ // Start user -- this will update state of mUserController
+ mUserController.startUser(TEST_USER_ID, true);
+ Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
+ assertNotNull(reportMsg);
+ UserState userState = (UserState) reportMsg.obj;
+ int oldUserId = reportMsg.arg1;
+ int newUserId = reportMsg.arg2;
+ // Call dispatchUserSwitch and verify that observer was called only once
+ mInjector.handler.clearAllRecordedMessages();
+ mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
+ Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
+ Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
+ Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
+ assertEquals("Unexpected message sent", expectedCodes, actualCodes);
+ Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
+ assertNotNull(conMsg);
+ userState = (UserState) conMsg.obj;
+ assertNotNull(userState);
+ assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
+ assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
+ assertEquals("Unexpected old user id", 0, conMsg.arg1);
+ assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
+ }
+
+ public void testDispatchUserSwitchBadReceiver() throws RemoteException {
+ // Prepare mock observer which doesn't notify the callback and register it
+ IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
+ when(observer.asBinder()).thenReturn(new Binder());
+ mUserController.registerUserSwitchObserver(observer, "mock");
+ // Start user -- this will update state of mUserController
+ mUserController.startUser(TEST_USER_ID, true);
+ Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
+ assertNotNull(reportMsg);
+ UserState userState = (UserState) reportMsg.obj;
+ int oldUserId = reportMsg.arg1;
+ int newUserId = reportMsg.arg2;
+ // Call dispatchUserSwitch and verify that observer was called only once
+ mInjector.handler.clearAllRecordedMessages();
+ mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
+ Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
+ // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
+ Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
+ assertTrue("No messages should be sent", actualCodes.isEmpty());
+ }
+
+ public void testContinueUserSwitch() throws RemoteException {
+ // Start user -- this will update state of mUserController
+ mUserController.startUser(TEST_USER_ID, true);
+ Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
+ assertNotNull(reportMsg);
+ UserState userState = (UserState) reportMsg.obj;
+ int oldUserId = reportMsg.arg1;
+ int newUserId = reportMsg.arg2;
+ mInjector.handler.clearAllRecordedMessages();
+ // Verify that continueUserSwitch worked as expected
+ mUserController.continueUserSwitch(userState, oldUserId, newUserId);
+ Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
+ Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
+ Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
+ assertEquals("Unexpected message sent", expectedCodes, actualCodes);
+ Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
+ assertNotNull(msg);
+ assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
}
private void setUpUser(int userId, int flags) {
@@ -89,7 +195,7 @@
private static class TestInjector extends UserController.Injector {
final Object lock = new Object();
- Handler handler;
+ TestHandler handler;
HandlerThread handlerThread;
UserManagerService userManagerMock;
UserManagerInternal userManagerInternalMock;
@@ -102,7 +208,7 @@
mCtx = ctx;
handlerThread = new HandlerThread(TAG);
handlerThread.start();
- handler = new Handler(handlerThread.getLooper());
+ handler = new TestHandler(handlerThread.getLooper());
userManagerMock = mock(UserManagerService.class);
userManagerInternalMock = mock(UserManagerInternal.class);
windowManagerMock = mock(WindowManagerService.class);
@@ -176,4 +282,41 @@
Log.i(TAG, "startHomeActivityLocked " + userId);
}
}
+
+ private static class TestHandler extends Handler {
+ private final List<Message> mMessages = new ArrayList<>();
+
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ Set<Integer> getMessageCodes() {
+ Set<Integer> result = new LinkedHashSet<>();
+ for (Message msg : mMessages) {
+ result.add(msg.what);
+ }
+ return result;
+ }
+
+ Message getMessageForCode(int what) {
+ for (Message msg : mMessages) {
+ if (msg.what == what) {
+ return msg;
+ }
+ }
+ return null;
+ }
+
+ void clearAllRecordedMessages() {
+ mMessages.clear();
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ Message copy = new Message();
+ copy.copyFrom(msg);
+ mMessages.add(copy);
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+ }
}
\ No newline at end of file