Merge "Add SilkFX demo app"
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 9f795a7..c40e025 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -19,7 +19,7 @@
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
- "collector-device-lib-platform",
+ "collector-device-lib",
],
data: [":perfetto_artifacts"],
platform_apis: true,
diff --git a/api/system-current.txt b/api/system-current.txt
index 56059dd..88fe40a 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12732,6 +12732,9 @@
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
+ method public default long getNetworkHandle();
+ method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -12871,6 +12874,7 @@
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ed717c4..4b7eda0 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
+import android.app.backup.BackupManager.OperationType;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupProgress;
import android.app.backup.BackupTransport;
@@ -666,7 +667,7 @@
// The rest of the 'list' options work with a restore session on the current transport
try {
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
@@ -821,7 +822,7 @@
try {
boolean didRestore = false;
- mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
+ mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
if (mRestore == null) {
System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index b1a62bf..9b67587 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -355,7 +355,36 @@
try {
// All packages, current transport
IRestoreSession binder =
- sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
+ sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
+ OperationType.BACKUP);
+ if (binder != null) {
+ session = new RestoreSession(mContext, binder);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "beginRestoreSession() couldn't connect");
+ }
+ }
+ return session;
+ }
+
+ /**
+ * Begin the process of restoring data from backup. See the
+ * {@link android.app.backup.RestoreSession} class for documentation on that process.
+ *
+ * @param operationType Type of the operation, see {@link OperationType}
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public RestoreSession beginRestoreSession(@OperationType int operationType) {
+ RestoreSession session = null;
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ // All packages, current transport
+ IRestoreSession binder =
+ sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
+ operationType);
if (binder != null) {
session = new RestoreSession(mContext, binder);
}
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 96b5dd5..e177a74 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -547,9 +547,11 @@
* set can be restored.
* @param transportID The name of the transport to use for the restore operation.
* May be null, in which case the current active transport is used.
+ * @param operationType Type of the operation, see {@link BackupManager#OperationType}
* @return An interface to the restore session, or null on error.
*/
- IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID);
+ IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID,
+ int operationType);
/**
* Notify the backup manager that a BackupAgent has completed the operation
diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java
new file mode 100644
index 0000000..39c5c85
--- /dev/null
+++ b/core/java/android/app/people/ConversationChannel.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+import android.app.NotificationChannel;
+import android.content.pm.ShortcutInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The non-customized notification channel of a conversation. It contains the information to render
+ * the conversation and allows the user to open and customize the conversation setting.
+ *
+ * @hide
+ */
+public final class ConversationChannel implements Parcelable {
+
+ private ShortcutInfo mShortcutInfo;
+ private NotificationChannel mParentNotificationChannel;
+ private long mLastEventTimestamp;
+ private boolean mHasActiveNotifications;
+
+ public static final Creator<ConversationChannel> CREATOR = new Creator<ConversationChannel>() {
+ @Override
+ public ConversationChannel createFromParcel(Parcel in) {
+ return new ConversationChannel(in);
+ }
+
+ @Override
+ public ConversationChannel[] newArray(int size) {
+ return new ConversationChannel[size];
+ }
+ };
+
+ public ConversationChannel(ShortcutInfo shortcutInfo,
+ NotificationChannel parentNotificationChannel, long lastEventTimestamp,
+ boolean hasActiveNotifications) {
+ mShortcutInfo = shortcutInfo;
+ mParentNotificationChannel = parentNotificationChannel;
+ mLastEventTimestamp = lastEventTimestamp;
+ mHasActiveNotifications = hasActiveNotifications;
+ }
+
+ public ConversationChannel(Parcel in) {
+ mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+ mParentNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
+ mLastEventTimestamp = in.readLong();
+ mHasActiveNotifications = in.readBoolean();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mShortcutInfo, flags);
+ dest.writeParcelable(mParentNotificationChannel, flags);
+ dest.writeLong(mLastEventTimestamp);
+ dest.writeBoolean(mHasActiveNotifications);
+ }
+
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ public NotificationChannel getParentNotificationChannel() {
+ return mParentNotificationChannel;
+ }
+
+ public long getLastEventTimestamp() {
+ return mLastEventTimestamp;
+ }
+
+ /**
+ * Whether this conversation has any active notifications. If it's true, the shortcut for this
+ * conversation can't be uncached until all its active notifications are dismissed.
+ */
+ public boolean hasActiveNotifications() {
+ return mHasActiveNotifications;
+ }
+}
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
new file mode 100644
index 0000000..61dac0d
--- /dev/null
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+import android.content.pm.ParceledListSlice;
+import android.net.Uri;
+import android.os.IBinder;
+
+/**
+ * System private API for talking with the people service.
+ * {@hide}
+ */
+interface IPeopleManager {
+ /**
+ * Returns the recent conversations. The conversations that have customized notification
+ * settings are excluded from the returned list.
+ */
+ ParceledListSlice getRecentConversations();
+
+ /**
+ * Removes the specified conversation from the recent conversations list and uncaches the
+ * shortcut associated with the conversation.
+ */
+ void removeRecentConversation(in String packageName, int userId, in String shortcutId);
+
+ /** Removes all the recent conversations and uncaches their cached shortcuts. */
+ void removeAllRecentConversations();
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 16cdf23..52b0467 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3496,6 +3496,7 @@
//@hide: TIME_ZONE_DETECTOR_SERVICE,
PERMISSION_SERVICE,
LIGHTS_SERVICE,
+ //@hide: PEOPLE_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -5189,6 +5190,14 @@
public static final String SMS_SERVICE = "sms";
/**
+ * Use with {@link #getSystemService(String)} to access people service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String PEOPLE_SERVICE = "people";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c383bc7..7f45c04 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -618,16 +618,20 @@
return false;
}
if (DEBUG) Log.d(TAG, "onStateChanged: " + state);
- updateState(state);
-
- boolean localStateChanged = !mState.equals(mLastDispatchedState,
- true /* excludingCaptionInsets */, true /* excludeInvisibleIme */);
mLastDispatchedState.set(state, true /* copySources */);
+ final InsetsState lastState = new InsetsState(mState, true /* copySources */);
+ updateState(state);
applyLocalVisibilityOverride();
- if (localStateChanged) {
- if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState);
+
+ if (!mState.equals(lastState, true /* excludingCaptionInsets */,
+ true /* excludeInvisibleIme */)) {
+ if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
+ }
+ if (!mState.equals(state, true /* excludingCaptionInsets */,
+ true /* excludeInvisibleIme */)) {
+ if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState);
updateRequestedState();
}
return true;
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index eb67191..e814ec6 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -29,7 +29,7 @@
oneway interface IWindowMagnificationConnection {
/**
- * Enables window magnification on specified display with given center and scale and animation.
+ * Enables window magnification on specifed display with specified center and scale.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -41,7 +41,7 @@
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
/**
- * Sets the scale of the window magnifier on specified display.
+ * Sets the scale of the window magnifier on specifed display.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -49,14 +49,14 @@
void setScale(int displayId, float scale);
/**
- * Disables window magnification on specified display with animation.
+ * Disables window magnification on specifed display.
*
* @param displayId The logical display id.
*/
void disableWindowMagnification(int displayId);
/**
- * Moves the window magnifier on the specified display. It has no effect while animating.
+ * Moves the window magnifier on the specifed display.
*
* @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
* current screen pixels.
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index 5ef450f..7e7b987 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-
+import android.net.Network;
/**
* Class to evaluate PAC scripts.
@@ -40,6 +40,20 @@
}
/**
+ * Returns PacProcessor instance associated with the {@link Network}.
+ * The host resolution is done on this {@link Network}.
+ *
+ * @param networkHandle a handle representing {@link Network} handle.
+ * @return PacProcessor instance for the specified network.
+ * @see Network#getNetworkHandle
+ * @see Network#fromNetworkHandle
+ */
+ @NonNull
+ static PacProcessor getInstanceForNetwork(long networkHandle) {
+ return WebViewFactory.getProvider().getPacProcessorForNetwork(networkHandle);
+ }
+
+ /**
* Set PAC script to use.
*
* @param script PAC script.
@@ -55,4 +69,23 @@
*/
@Nullable
String findProxyForUrl(@NonNull String url);
+
+ /**
+ * Stops support for this {@link PacProcessor} and release its resources.
+ * No methods of this class must be called after calling this method.
+ */
+ default void releasePacProcessor() {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Returns a network handle associated with this {@link PacProcessor}.
+ *
+ * @return a network handle or 0 if a network is unspecified.
+ * @see Network#getNetworkHandle
+ * @see Network#fromNetworkHandle
+ */
+ default long getNetworkHandle() {
+ throw new UnsupportedOperationException("Not implemented");
+ }
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index f7c3ec0..f1863e3 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
+import android.net.Network;
import android.net.Uri;
import java.util.List;
@@ -175,7 +176,7 @@
WebViewDatabase getWebViewDatabase(Context context);
/**
- * Gets the singleton PacProcessor instance.
+ * Gets the default PacProcessor instance.
* @return the PacProcessor instance
*/
@NonNull
@@ -184,6 +185,20 @@
}
/**
+ * Returns PacProcessor instance associated with the {@link Network}.
+ * The host resolution is done on this {@link Network}.
+ *
+ * @param networkHandle a network handle representing the {@link Network}.
+ * @return the {@link PacProcessor} instance associated with {@link Network}.
+ * @see Network#getNetworkHandle
+ * @see Network#fromNetworkHandle
+ */
+ @NonNull
+ default PacProcessor getPacProcessorForNetwork(long networkHandle) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
* Gets the classloader used to load internal WebView implementation classes. This interface
* should only be used by the WebView Support Library.
*/
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 801cd4d..af02b7b 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -27,6 +27,7 @@
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -40,8 +41,11 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -124,7 +128,7 @@
}
mTestClock = new OffsettableClock();
mTestHandler = new TestHandler(null, mTestClock);
- mTestHost = new TestHost(mViewRoot);
+ mTestHost = spy(new TestHost(mViewRoot));
mController = new InsetsController(mTestHost, (controller, type) -> {
if (type == ITYPE_IME) {
return new InsetsSourceConsumer(type, controller.getState(),
@@ -745,6 +749,99 @@
});
}
+ @Test
+ public void testInsetsChangedCount_controlSystemBars() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ prepareControls();
+
+ // Hiding visible system bars should only causes insets change once for each bar.
+ clearInvocations(mTestHost);
+ mController.hide(statusBars() | navigationBars());
+ verify(mTestHost, times(2)).notifyInsetsChanged();
+
+ // Sending the same insets state should not cause insets change.
+ // This simulates the callback from server after hiding system bars.
+ clearInvocations(mTestHost);
+ mController.onStateChanged(mController.getState());
+ verify(mTestHost, never()).notifyInsetsChanged();
+
+ // Showing invisible system bars should only causes insets change once for each bar.
+ clearInvocations(mTestHost);
+ mController.show(statusBars() | navigationBars());
+ verify(mTestHost, times(2)).notifyInsetsChanged();
+
+ // Sending the same insets state should not cause insets change.
+ // This simulates the callback from server after showing system bars.
+ clearInvocations(mTestHost);
+ mController.onStateChanged(mController.getState());
+ verify(mTestHost, never()).notifyInsetsChanged();
+ });
+ }
+
+ @Test
+ public void testInsetsChangedCount_controlIme() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ prepareControls();
+
+ // Showing invisible ime should only causes insets change once.
+ clearInvocations(mTestHost);
+ mController.show(ime(), true /* fromIme */);
+ verify(mTestHost, times(1)).notifyInsetsChanged();
+
+ // Sending the same insets state should not cause insets change.
+ // This simulates the callback from server after showing ime.
+ clearInvocations(mTestHost);
+ mController.onStateChanged(mController.getState());
+ verify(mTestHost, never()).notifyInsetsChanged();
+
+ // Hiding visible ime should only causes insets change once.
+ clearInvocations(mTestHost);
+ mController.hide(ime());
+ verify(mTestHost, times(1)).notifyInsetsChanged();
+
+ // Sending the same insets state should not cause insets change.
+ // This simulates the callback from server after hiding ime.
+ clearInvocations(mTestHost);
+ mController.onStateChanged(mController.getState());
+ verify(mTestHost, never()).notifyInsetsChanged();
+ });
+ }
+
+ @Test
+ public void testInsetsChangedCount_onStateChanged() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final InsetsState localState = mController.getState();
+
+ // Changing status bar frame should cause notifyInsetsChanged.
+ clearInvocations(mTestHost);
+ InsetsState newState = new InsetsState(localState, true /* copySources */);
+ newState.getSource(ITYPE_STATUS_BAR).getFrame().bottom++;
+ mController.onStateChanged(newState);
+ verify(mTestHost, times(1)).notifyInsetsChanged();
+
+ // Changing status bar visibility should cause notifyInsetsChanged.
+ clearInvocations(mTestHost);
+ newState = new InsetsState(localState, true /* copySources */);
+ newState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ mController.onStateChanged(newState);
+ verify(mTestHost, times(1)).notifyInsetsChanged();
+
+ // Changing invisible IME frame should not cause notifyInsetsChanged.
+ clearInvocations(mTestHost);
+ newState = new InsetsState(localState, true /* copySources */);
+ newState.getSource(ITYPE_IME).getFrame().top--;
+ mController.onStateChanged(newState);
+ verify(mTestHost, never()).notifyInsetsChanged();
+
+ // Changing IME visibility should cause notifyInsetsChanged.
+ clearInvocations(mTestHost);
+ newState = new InsetsState(localState, true /* copySources */);
+ newState.getSource(ITYPE_IME).setVisible(true);
+ mController.onStateChanged(newState);
+ verify(mTestHost, times(1)).notifyInsetsChanged();
+ });
+ }
+
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
@@ -777,7 +874,7 @@
return controls;
}
- private static class TestHost extends ViewRootInsetsControllerHost {
+ public static class TestHost extends ViewRootInsetsControllerHost {
private InsetsState mModifiedState = new InsetsState();
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 844e929..10887fa 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -11575,6 +11575,9 @@
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
+ method public default long getNetworkHandle();
+ method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -11714,6 +11717,7 @@
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index d5f74a8..816bcf8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -53,8 +53,8 @@
ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION;
@VisibleForTesting
- protected WindowMagnificationAnimationController mWindowMagnificationAnimationController;
- private final ModeSwitchesController mModeSwitchesController;
+ protected WindowMagnificationController mWindowMagnificationController;
+ protected final ModeSwitchesController mModeSwitchesController;
private final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
private final CommandQueue mCommandQueue;
@@ -72,11 +72,6 @@
Context.ACCESSIBILITY_SERVICE);
mCommandQueue = commandQueue;
mModeSwitchesController = modeSwitchesController;
- final WindowMagnificationController controller = new WindowMagnificationController(mContext,
- mHandler, new SfVsyncFrameCallbackProvider(), null,
- new SurfaceControl.Transaction(), this);
- mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
- mContext, controller);
}
@Override
@@ -86,7 +81,9 @@
return;
}
mLastConfiguration.setTo(newConfig);
- mWindowMagnificationAnimationController.onConfigurationChanged(configDiff);
+ if (mWindowMagnificationController != null) {
+ mWindowMagnificationController.onConfigurationChanged(configDiff);
+ }
if (mModeSwitchesController != null) {
mModeSwitchesController.onConfigurationChanged(configDiff);
}
@@ -100,25 +97,39 @@
@MainThread
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
+ if (mWindowMagnificationController == null) {
+ mWindowMagnificationController = new WindowMagnificationController(mContext,
+ mHandler,
+ new SfVsyncFrameCallbackProvider(),
+ null, new SurfaceControl.Transaction(),
+ this);
+ }
+ mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
}
@MainThread
void setScale(int displayId, float scale) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.setScale(scale);
+ if (mWindowMagnificationController != null) {
+ mWindowMagnificationController.setScale(scale);
+ }
}
@MainThread
void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY);
+ if (mWindowMagnificationController != null) {
+ mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY);
+ }
}
@MainThread
void disableWindowMagnification(int displayId) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.deleteWindowMagnification();
+ if (mWindowMagnificationController != null) {
+ mWindowMagnificationController.deleteWindowMagnification();
+ }
+ mWindowMagnificationController = null;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
deleted file mode 100644
index ae51623..0000000
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.accessibility;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.annotation.IntDef;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-import android.view.animation.AccelerateInterpolator;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Provides same functionality of {@link WindowMagnificationController}. Some methods run with
- * the animation.
- */
-class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener,
- Animator.AnimatorListener {
-
- private static final String TAG = "WindowMagnificationBridge";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING})
- @interface MagnificationState {}
-
- //The window magnification is disabled.
- private static final int STATE_DISABLED = 0;
- //The window magnification is enabled.
- private static final int STATE_ENABLED = 1;
- //The window magnification is going to be disabled when the animation is end.
- private static final int STATE_DISABLING = 2;
- //The animation is running for enabling the window magnification.
- private static final int STATE_ENABLING = 3;
-
- private final WindowMagnificationController mController;
- private final ValueAnimator mValueAnimator;
- private final AnimationSpec mStartSpec = new AnimationSpec();
- private final AnimationSpec mEndSpec = new AnimationSpec();
- private final Context mContext;
-
- @MagnificationState
- private int mState = STATE_DISABLED;
-
- WindowMagnificationAnimationController(
- Context context, WindowMagnificationController controller) {
- this(context, controller, newValueAnimator(context.getResources()));
- }
-
- @VisibleForTesting
- WindowMagnificationAnimationController(Context context,
- WindowMagnificationController controller, ValueAnimator valueAnimator) {
- mContext = context;
- mController = controller;
- mValueAnimator = valueAnimator;
- mValueAnimator.addUpdateListener(this);
- mValueAnimator.addListener(this);
- }
-
- /**
- * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
- * with transition animation. If the window magnification is not enabled, the scale will start
- * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
- * {@code STATE_DISABLING}, the animation runs in reverse.
- *
- * @param scale the target scale, or {@link Float#NaN} to leave unchanged.
- * @param centerX the screen-relative X coordinate around which to center,
- * or {@link Float#NaN} to leave unchanged.
- * @param centerY the screen-relative Y coordinate around which to center,
- * or {@link Float#NaN} to leave unchanged.
- *
- * @see #onAnimationUpdate(ValueAnimator)
- */
- void enableWindowMagnification(float scale, float centerX, float centerY) {
- if (mState == STATE_ENABLING) {
- mValueAnimator.cancel();
- }
- setupEnableAnimationSpecs(scale, centerX, centerY);
-
- if (mEndSpec.equals(mStartSpec)) {
- setState(STATE_ENABLED);
- } else {
- if (mState == STATE_DISABLING) {
- mValueAnimator.reverse();
- } else {
- mValueAnimator.start();
- }
- setState(STATE_ENABLING);
- }
- }
-
- private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) {
- final float currentScale = mController.getScale();
- final float currentCenterX = mController.getCenterX();
- final float currentCenterY = mController.getCenterY();
-
- if (mState == STATE_DISABLED) {
- //We don't need to offset the center during the animation.
- mStartSpec.set(/* scale*/ 1.0f, centerX, centerY);
- mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger(
- R.integer.magnification_default_scale) : scale, centerX, centerY);
- } else {
- mStartSpec.set(currentScale, currentCenterX, currentCenterY);
- mEndSpec.set(Float.isNaN(scale) ? currentScale : scale,
- Float.isNaN(centerX) ? currentCenterX : centerX,
- Float.isNaN(centerY) ? currentCenterY : centerY);
- }
- if (DEBUG) {
- Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = "
- + mEndSpec);
- }
- }
-
- /**
- * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is
- * running, it has no effect.
- */
- void setScale(float scale) {
- if (mValueAnimator.isRunning()) {
- return;
- }
- mController.setScale(scale);
- }
-
- /**
- * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
- * animation. If the window magnification is enabling, it runs the animation in reverse.
- */
- void deleteWindowMagnification() {
- if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
- return;
- }
- mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
- mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN);
-
- mValueAnimator.reverse();
- setState(STATE_DISABLING);
- }
-
- /**
- * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
- * animation is running, it has no effect.
- * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
- * current screen pixels.
- * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
- * current screen pixels.
- */
- void moveWindowMagnifier(float offsetX, float offsetY) {
- if (mValueAnimator.isRunning()) {
- return;
- }
- mController.moveWindowMagnifier(offsetX, offsetY);
- }
-
- void onConfigurationChanged(int configDiff) {
- mController.onConfigurationChanged(configDiff);
- }
-
- private void setState(@MagnificationState int state) {
- if (DEBUG) {
- Log.d(TAG, "setState from " + mState + " to " + state);
- }
- mState = state;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mState == STATE_DISABLING) {
- mController.deleteWindowMagnification();
- setState(STATE_DISABLED);
- } else if (mState == STATE_ENABLING) {
- setState(STATE_ENABLED);
- } else {
- Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float fract = animation.getAnimatedFraction();
- final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract;
- final float centerX =
- mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
- final float centerY =
- mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
- mController.enableWindowMagnification(sentScale, centerX, centerY);
- }
-
- private static ValueAnimator newValueAnimator(Resources resources) {
- final ValueAnimator valueAnimator = new ValueAnimator();
- valueAnimator.setDuration(
- resources.getInteger(com.android.internal.R.integer.config_longAnimTime));
- valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
- valueAnimator.setFloatValues(0.0f, 1.0f);
- return valueAnimator;
- }
-
- private static class AnimationSpec {
- private float mScale = Float.NaN;
- private float mCenterX = Float.NaN;
- private float mCenterY = Float.NaN;
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
-
- if (other == null || getClass() != other.getClass()) {
- return false;
- }
-
- final AnimationSpec s = (AnimationSpec) other;
- return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY;
- }
-
- @Override
- public int hashCode() {
- int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0);
- result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0);
- result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0);
- return result;
- }
-
- void set(float scale, float centerX, float centerY) {
- mScale = scale;
- mCenterX = centerX;
- mCenterY = centerY;
- }
-
- @Override
- public String toString() {
- return "AnimationSpec{"
- + "mScale=" + mScale
- + ", mCenterX=" + mCenterX
- + ", mCenterY=" + mCenterY
- + '}';
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 6d3e8ba..798b751 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -150,7 +150,7 @@
mMirrorViewGeometryVsyncCallback =
l -> {
- if (isWindowVisible() && mMirrorSurface != null) {
+ if (mMirrorView != null && mMirrorSurface != null) {
calculateSourceBounds(mMagnificationFrame, mScale);
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
@@ -502,7 +502,7 @@
/**
* Enables window magnification with specified parameters.
*
- * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param scale the target scale
* @param centerX the screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param centerY the screen-relative Y coordinate around which to center,
@@ -513,10 +513,10 @@
: centerX - mMagnificationFrame.exactCenterX();
final float offsetY = Float.isNaN(centerY) ? 0
: centerY - mMagnificationFrame.exactCenterY();
- mScale = Float.isNaN(scale) ? mScale : scale;
+ mScale = scale;
setMagnificationFrameBoundary();
updateMagnificationFramePosition((int) offsetX, (int) offsetY);
- if (!isWindowVisible()) {
+ if (mMirrorView == null) {
createMirrorWindow();
showControls();
} else {
@@ -527,10 +527,10 @@
/**
* Sets the scale of the magnified region if it's visible.
*
- * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param scale the target scale
*/
void setScale(float scale) {
- if (!isWindowVisible() || mScale == scale) {
+ if (mMirrorView == null || mScale == scale) {
return;
}
enableWindowMagnification(scale, Float.NaN, Float.NaN);
@@ -552,35 +552,4 @@
modifyWindowMagnification(mTransaction);
}
}
-
- /**
- * Gets the scale.
- * @return {@link Float#NaN} if the window is invisible.
- */
- float getScale() {
- return isWindowVisible() ? mScale : Float.NaN;
- }
-
- /**
- * Returns the screen-relative X coordinate of the center of the magnified bounds.
- *
- * @return the X coordinate. {@link Float#NaN} if the window is invisible.
- */
- float getCenterX() {
- return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN;
- }
-
- /**
- * Returns the screen-relative Y coordinate of the center of the magnified bounds.
- *
- * @return the Y coordinate. {@link Float#NaN} if the window is invisible.
- */
- float getCenterY() {
- return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN;
- }
-
- //The window is visible when it is existed.
- private boolean isWindowVisible() {
- return mMirrorView != null;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index d0f6181..fa0d2ba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -310,7 +310,6 @@
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
- mActivityViewContainer.setBackgroundColor(Color.WHITE);
mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
@@ -439,9 +438,11 @@
}
void applyThemeAttrs() {
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.dialogCornerRadius});
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ android.R.attr.dialogCornerRadius,
+ android.R.attr.colorBackgroundFloating});
mCornerRadius = ta.getDimensionPixelSize(0, 0);
+ mActivityViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE));
ta.recycle();
if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index 53b369c..eb47645 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -34,6 +34,7 @@
private ContextButtonListener mListener;
private ContextualButtonGroup mGroup;
+ protected final Context mLightContext;
protected final @DrawableRes int mIconResId;
/**
@@ -42,8 +43,10 @@
* @param buttonResId the button view from xml layout
* @param iconResId icon resource to be used
*/
- public ContextualButton(@IdRes int buttonResId, @DrawableRes int iconResId) {
+ public ContextualButton(@IdRes int buttonResId, Context lightContext,
+ @DrawableRes int iconResId) {
super(buttonResId);
+ mLightContext = lightContext;
mIconResId = iconResId;
}
@@ -117,17 +120,8 @@
}
protected KeyButtonDrawable getNewDrawable(int lightIconColor, int darkIconColor) {
- return KeyButtonDrawable.create(getContext().getApplicationContext(), lightIconColor,
- darkIconColor, mIconResId, false /* shadow */, null /* ovalBackground */);
- }
-
- /**
- * This context is from the view that could be stale after rotation or config change. To get
- * correct resources use getApplicationContext() as well.
- * @return current view context
- */
- protected Context getContext() {
- return getCurrentView().getContext();
+ return KeyButtonDrawable.create(mLightContext, lightIconColor, darkIconColor, mIconResId,
+ false /* shadow */, null /* ovalBackground */);
}
public interface ContextButtonListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 62970525..8c5e2ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -375,6 +375,34 @@
}
};
+ private static class NavBarViewAttachedListener implements View.OnAttachStateChangeListener {
+ private NavigationBarFragment mFragment;
+ private FragmentListener mListener;
+
+ NavBarViewAttachedListener(NavigationBarFragment fragment, FragmentListener listener) {
+ mFragment = fragment;
+ mListener = listener;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
+ fragmentHost.getFragmentManager().beginTransaction()
+ .replace(R.id.navigation_bar_frame, mFragment, TAG)
+ .commit();
+ fragmentHost.addTagListener(TAG, mListener);
+ mFragment = null;
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
+ fragmentHost.removeTagListener(TAG, mListener);
+ FragmentHostManager.removeAndDestroy(v);
+ v.removeOnAttachStateChangeListener(this);
+ }
+ }
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -1470,26 +1498,10 @@
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
if (navigationBarView == null) return null;
- navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- final NavigationBarFragment fragment =
- FragmentHostManager.get(v).create(NavigationBarFragment.class);
- final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
- fragmentHost.getFragmentManager().beginTransaction()
- .replace(R.id.navigation_bar_frame, fragment, TAG)
- .commit();
- fragmentHost.addTagListener(TAG, listener);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
- fragmentHost.removeTagListener(TAG, listener);
- FragmentHostManager.removeAndDestroy(v);
- navigationBarView.removeOnAttachStateChangeListener(this);
- }
- });
+ NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
+ .create(NavigationBarFragment.class);
+ navigationBarView.addOnAttachStateChangeListener(new NavBarViewAttachedListener(fragment,
+ listener));
context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
return navigationBarView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 84512ac..0b4a2b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -295,11 +295,12 @@
// Set up the context group of buttons
mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
- R.drawable.ic_ime_switcher_default);
+ mLightContext, R.drawable.ic_ime_switcher_default);
final RotationContextButton rotateSuggestionButton = new RotationContextButton(
- R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button_ccw_start_0);
+ R.id.rotate_suggestion, mLightContext,
+ R.drawable.ic_sysbar_rotate_button_ccw_start_0);
final ContextualButton accessibilityButton =
- new ContextualButton(R.id.accessibility_button,
+ new ContextualButton(R.id.accessibility_button, mLightContext,
R.drawable.ic_sysbar_accessibility_button);
mContextualButtonGroup.addButton(imeSwitcherButton);
if (!isGesturalMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index f83cdd4..b0630a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -283,7 +283,6 @@
return;
}
- // TODO: Remove styles?
// Prepare to show the navbar icon by updating the icon style to change anim params
mLastRotationSuggestion = rotation; // Remember rotation for click
final boolean rotationCCW = isRotationAnimationCCW(windowRotation, rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index d7e95e4..08aeb04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -18,6 +18,7 @@
import android.annotation.DrawableRes;
import android.annotation.IdRes;
+import android.content.Context;
import android.view.View;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -28,8 +29,12 @@
private RotationButtonController mRotationButtonController;
- public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId) {
- super(buttonResId, iconResId);
+ /**
+ * @param lightContext the context to use to load the icon resource
+ */
+ public RotationContextButton(@IdRes int buttonResId, Context lightContext,
+ @DrawableRes int iconResId) {
+ super(buttonResId, lightContext, iconResId);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index b5f98ad..89297fd 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -54,7 +54,7 @@
String uriString = intent.getStringExtra("uri");
mUri = (uriString == null ? null : Uri.parse(uriString));
- // sanity check before displaying dialog
+ // Exception check before displaying dialog
if (mUri == null) {
Log.e(TAG, "could not parse Uri " + uriString);
finish();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index ac567e0..fbc8e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -25,7 +25,6 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -48,7 +47,6 @@
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class IWindowMagnificationConnectionTest extends SysuiTestCase {
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
@@ -59,7 +57,7 @@
@Mock
private IWindowMagnificationConnectionCallback mConnectionCallback;
@Mock
- private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+ private WindowMagnificationController mWindowMagnificationController;
@Mock
private ModeSwitchesController mModeSwitchesController;
private IWindowMagnificationConnection mIWindowMagnificationConnection;
@@ -76,8 +74,7 @@
any(IWindowMagnificationConnection.class));
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
- mWindowMagnification.mWindowMagnificationAnimationController =
- mWindowMagnificationAnimationController;
+ mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController;
mWindowMagnification.requestWindowMagnificationConnection(true);
assertNotNull(mIWindowMagnificationConnection);
mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback);
@@ -89,7 +86,7 @@
Float.NaN);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
+ verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN,
Float.NaN);
}
@@ -102,7 +99,7 @@
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
+ verify(mWindowMagnificationController).deleteWindowMagnification();
}
@Test
@@ -110,7 +107,7 @@
mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).setScale(3.0f);
+ verify(mWindowMagnificationController).setScale(3.0f);
}
@Test
@@ -118,7 +115,7 @@
mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f);
+ verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
deleted file mode 100644
index add0843..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.accessibility;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.animation.ValueAnimator;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.testing.AndroidTestingRunner;
-import android.view.SurfaceControl;
-import android.view.animation.AccelerateInterpolator;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-
-@MediumTest
-@RunWith(AndroidTestingRunner.class)
-public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
-
- private static final float DEFAULT_SCALE = 3.0f;
- private static final float DEFAULT_CENTER_X = 400.0f;
- private static final float DEFAULT_CENTER_Y = 500.0f;
- private static final long ANIMATION_DURATION_MS = 100;
-
- private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
- private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
- private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0);
- private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
- private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
- private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
-
- @Mock
- Handler mHandler;
- @Mock
- SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- @Mock
- WindowMagnifierCallback mWindowMagnifierCallback;
-
- private SpyWindowMagnificationController mController;
- private WindowMagnificationController mSpyController;
- private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
- private Instrumentation mInstrumentation;
- private long mWaitingAnimationPeriod;
- private long mWaitIntermediateAnimationPeriod;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50;
- mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
- mController = new SpyWindowMagnificationController(mContext, mHandler,
- mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
- mWindowMagnifierCallback);
- mSpyController = mController.getSpyController();
- mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
- mContext, mController, newValueAnimator());
- }
-
- @Test
- public void enableWindowMagnification_disabled_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(
- mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- verifyStartValue(mScaleCaptor, 1.0f);
- verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
- verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
- verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
- }
-
- @Test
- public void enableWindowMagnification_enabling_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
- final float targetScale = DEFAULT_SCALE + 1.0f;
- final float targetCenterX = DEFAULT_CENTER_X + 100;
- final float targetCenterY = DEFAULT_CENTER_Y + 100;
-
- mInstrumentation.runOnMainSync(() -> {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- });
-
- SystemClock.sleep(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- verifyStartValue(mScaleCaptor, mCurrentScale.get());
- verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
- verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
- verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
- }
-
- @Test
- public void enableWindowMagnification_disabling_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
- deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
- final float targetScale = DEFAULT_SCALE + 1.0f;
- final float targetCenterX = DEFAULT_CENTER_X + 100;
- final float targetCenterY = DEFAULT_CENTER_Y + 100;
-
- mInstrumentation.runOnMainSync(
- () -> {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY);
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- });
- SystemClock.sleep(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(
- mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- //Animating in reverse, so we only check if the start values are greater than current.
- assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get());
- assertEquals(targetScale, mScaleCaptor.getValue(), 0f);
- assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get());
- assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f);
- assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
- assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
- verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
- }
-
- @Test
- public void enableWindowMagnificationWithSameScale_doNothing() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
- anyFloat());
- }
-
- @Test
- public void setScale_enabled_expectedScale() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- mInstrumentation.runOnMainSync(
- () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
-
- verify(mSpyController).setScale(DEFAULT_SCALE + 1);
- verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
- }
-
- @Test
- public void deleteWindowMagnification_enabled_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- verify(mSpyController).deleteWindowMagnification();
- verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
- verifyStartValue(mCenterXCaptor, Float.NaN);
- verifyStartValue(mCenterYCaptor, Float.NaN);
- verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
- }
-
- @Test
- public void deleteWindowMagnification_disabled_doNothing() {
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- Mockito.verifyNoMoreInteractions(mSpyController);
- }
-
- @Test
- public void deleteWindowMagnification_enabling_checkStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
-
- //It just reverse the animation, so we don't need to wait the whole duration.
- mInstrumentation.runOnMainSync(
- () -> {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.deleteWindowMagnification();
- mCurrentScale.set(mController.getScale());
- mCurrentCenterX.set(mController.getCenterX());
- mCurrentCenterY.set(mController.getCenterY());
- });
- SystemClock.sleep(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- verify(mSpyController).deleteWindowMagnification();
-
- //The animation is in verse, so we only check the start values should no be greater than
- // the current one.
- assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get());
- assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
- verifyStartValue(mCenterXCaptor, Float.NaN);
- verifyStartValue(mCenterYCaptor, Float.NaN);
- verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
- }
-
- @Test
- public void deleteWindowMagnification_disabling_checkStartAndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
- deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
-
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
- mCenterXCaptor.capture(), mCenterYCaptor.capture());
- verify(mSpyController).deleteWindowMagnification();
- assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
- verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
- }
-
- @Test
- public void moveWindowMagnifier_enabled() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
-
- mInstrumentation.runOnMainSync(
- () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
-
- verify(mSpyController).moveWindowMagnifier(100f, 200f);
- verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
- }
-
- @Test
- public void onConfigurationChanged_passThrough() {
- mWindowMagnificationAnimationController.onConfigurationChanged(100);
-
- verify(mSpyController).onConfigurationChanged(100);
- }
- private void verifyFinalSpec(float expectedScale, float expectedCenterX,
- float expectedCenterY) {
- assertEquals(expectedScale, mController.getScale(), 0f);
- assertEquals(expectedCenterX, mController.getCenterX(), 0f);
- assertEquals(expectedCenterY, mController.getCenterY(), 0f);
- }
-
- private void enableWindowMagnificationAndWaitAnimating(long duration) {
- mInstrumentation.runOnMainSync(
- () -> {
- Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
- DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
- });
- SystemClock.sleep(duration);
- }
-
- private void deleteWindowMagnificationAndWaitAnimating(long duration) {
- mInstrumentation.runOnMainSync(
- () -> {
- resetMockObjects();
- mWindowMagnificationAnimationController.deleteWindowMagnification();
- });
- SystemClock.sleep(duration);
- }
-
- private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
- assertEquals(startValue, captor.getAllValues().get(0), 0f);
- }
-
- private void resetMockObjects() {
- Mockito.reset(mSpyController);
- }
-
- /**
- * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it
- * directly.
- */
- private static class SpyWindowMagnificationController extends WindowMagnificationController {
- private WindowMagnificationController mSpyController;
-
- SpyWindowMagnificationController(Context context, Handler handler,
- SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
- MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
- WindowMagnifierCallback callback) {
- super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
- callback);
- mSpyController = Mockito.mock(WindowMagnificationController.class);
- }
-
- WindowMagnificationController getSpyController() {
- return mSpyController;
- }
-
- @Override
- void enableWindowMagnification(float scale, float centerX, float centerY) {
- super.enableWindowMagnification(scale, centerX, centerY);
- mSpyController.enableWindowMagnification(scale, centerX, centerY);
- }
-
- @Override
- void deleteWindowMagnification() {
- super.deleteWindowMagnification();
- mSpyController.deleteWindowMagnification();
- }
-
- @Override
- void moveWindowMagnifier(float offsetX, float offsetY) {
- super.moveWindowMagnifier(offsetX, offsetX);
- mSpyController.moveWindowMagnifier(offsetX, offsetY);
- }
-
- @Override
- void setScale(float scale) {
- super.setScale(scale);
- mSpyController.setScale(scale);
- }
-
- @Override
- void onConfigurationChanged(int configDiff) {
- super.onConfigurationChanged(configDiff);
- mSpyController.onConfigurationChanged(configDiff);
- }
-
- }
-
- private static ValueAnimator newValueAnimator() {
- final ValueAnimator valueAnimator = new ValueAnimator();
- valueAnimator.setDuration(ANIMATION_DURATION_MS);
- valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
- valueAnimator.setFloatValues(0.0f, 1.0f);
- return valueAnimator;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 1515cec..2007fbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -18,7 +18,6 @@
import static android.view.Choreographer.FrameCallback;
-import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
@@ -84,8 +83,9 @@
@After
public void tearDown() {
- mInstrumentation.runOnMainSync(
- () -> mWindowMagnificationController.deleteWindowMagnification());
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.deleteWindowMagnification();
+ });
}
@Test
@@ -121,18 +121,4 @@
verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
}
-
- @Test
- public void setScale_expectedValue() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
- Float.NaN);
- });
-
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.setScale(3.0f);
- });
-
- assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 936558b..4136013 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -26,7 +26,6 @@
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -46,7 +45,6 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class WindowMagnificationTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
index b5060ee..1fb28f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -65,9 +65,9 @@
mDependency.injectMockDependency(AssistManager.class);
mGroup = new ContextualButtonGroup(GROUP_ID);
- mBtn0 = new ContextualButton(BUTTON_0_ID, ICON_RES_ID);
- mBtn1 = new ContextualButton(BUTTON_1_ID, ICON_RES_ID);
- mBtn2 = new ContextualButton(BUTTON_2_ID, ICON_RES_ID);
+ mBtn0 = new ContextualButton(BUTTON_0_ID, mContext, ICON_RES_ID);
+ mBtn1 = new ContextualButton(BUTTON_1_ID, mContext, ICON_RES_ID);
+ mBtn2 = new ContextualButton(BUTTON_2_ID, mContext, ICON_RES_ID);
// Order of adding buttons to group determines the priority, ascending priority order
mGroup.addButton(mBtn0);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 3ee5b28..bd25f2b 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -25,12 +25,10 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Point;
import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
-import android.view.Display;
import android.view.MotionEvent;
import com.android.internal.annotations.VisibleForTesting;
@@ -92,8 +90,6 @@
private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate;
private final int mDisplayId;
- private final Context mContext;
- private final Point mTempPoint = new Point();
private final Queue<MotionEvent> mDebugOutputEventHistory;
@@ -111,7 +107,7 @@
Slog.i(LOG_TAG,
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
}
- mContext = context;
+
mWindowMagnificationMgr = windowMagnificationMgr;
mDetectShortcutTrigger = detectShortcutTrigger;
mDisplayId = displayId;
@@ -188,14 +184,7 @@
if (!mDetectShortcutTrigger) {
return;
}
- final Point screenSize = mTempPoint;
- getScreenSize(mTempPoint);
- toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
- }
-
- private void getScreenSize(Point outSize) {
- final Display display = mContext.getDisplay();
- display.getRealSize(outSize);
+ toggleMagnification(Float.NaN, Float.NaN);
}
@Override
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 12e6e10..186812b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1239,9 +1239,10 @@
@Override
public IRestoreSession beginRestoreSessionForUser(
- int userId, String packageName, String transportID) throws RemoteException {
+ int userId, String packageName, String transportID,
+ @OperationType int operationType) throws RemoteException {
return isUserReadyForBackup(userId)
- ? beginRestoreSession(userId, packageName, transportID) : null;
+ ? beginRestoreSession(userId, packageName, transportID, operationType) : null;
}
/**
@@ -1250,13 +1251,15 @@
*/
@Nullable
public IRestoreSession beginRestoreSession(
- @UserIdInt int userId, String packageName, String transportName) {
+ @UserIdInt int userId, String packageName, String transportName,
+ @OperationType int operationType) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
return userBackupManagerService == null
? null
- : userBackupManagerService.beginRestoreSession(packageName, transportName);
+ : userBackupManagerService.beginRestoreSession(packageName, transportName,
+ operationType);
}
@Override
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 3ab81cb..27a280a 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3973,7 +3973,8 @@
restoreSet,
packageName,
token,
- listener);
+ listener,
+ mScheduledBackupEligibility);
mBackupHandler.sendMessage(msg);
} catch (Exception e) {
// Calling into the transport broke; back off and proceed with the installation.
@@ -4002,13 +4003,15 @@
}
/** Hand off a restore session. */
- public IRestoreSession beginRestoreSession(String packageName, String transport) {
+ public IRestoreSession beginRestoreSession(String packageName, String transport,
+ @OperationType int operationType) {
if (DEBUG) {
Slog.v(
TAG,
addUserIdToLogMessage(
mUserId,
- "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
+ "beginRestoreSession: pkg=" + packageName + " transport=" + transport
+ + "operationType=" + operationType));
}
boolean needPermission = true;
@@ -4065,7 +4068,8 @@
"Restore session requested but currently running backups"));
return null;
}
- mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport);
+ mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport,
+ getEligibilityRulesForOperation(operationType));
mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
}
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 1bb4349..100dbae 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -305,8 +305,7 @@
params.isSystemRestore,
params.filterSet,
params.listener,
- backupManagerService.getEligibilityRulesForOperation(
- OperationType.BACKUP));
+ params.backupEligibilityRules);
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.isRestoreInProgress()) {
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index a6fea6c..a08a1f8 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -23,6 +23,7 @@
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import java.util.Map;
import java.util.Set;
@@ -37,6 +38,7 @@
public final boolean isSystemRestore;
@Nullable public final String[] filterSet;
public final OnTaskFinishedListener listener;
+ public final BackupEligibilityRules backupEligibilityRules;
/**
* No kill after restore.
@@ -47,7 +49,8 @@
IBackupManagerMonitor monitor,
long token,
PackageInfo packageInfo,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules eligibilityRules) {
return new RestoreParams(
transportClient,
observer,
@@ -57,7 +60,8 @@
/* pmToken */ 0,
/* isSystemRestore */ false,
/* filterSet */ null,
- listener);
+ listener,
+ eligibilityRules);
}
/**
@@ -70,7 +74,8 @@
long token,
String packageName,
int pmToken,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
String[] filterSet = {packageName};
return new RestoreParams(
transportClient,
@@ -81,7 +86,8 @@
pmToken,
/* isSystemRestore */ false,
filterSet,
- listener);
+ listener,
+ backupEligibilityRules);
}
/**
@@ -92,7 +98,8 @@
IRestoreObserver observer,
IBackupManagerMonitor monitor,
long token,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
return new RestoreParams(
transportClient,
observer,
@@ -102,7 +109,8 @@
/* pmToken */ 0,
/* isSystemRestore */ true,
/* filterSet */ null,
- listener);
+ listener,
+ backupEligibilityRules);
}
/**
@@ -115,7 +123,8 @@
long token,
String[] filterSet,
boolean isSystemRestore,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
return new RestoreParams(
transportClient,
observer,
@@ -125,7 +134,8 @@
/* pmToken */ 0,
isSystemRestore,
filterSet,
- listener);
+ listener,
+ backupEligibilityRules);
}
private RestoreParams(
@@ -137,7 +147,8 @@
int pmToken,
boolean isSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
this.transportClient = transportClient;
this.observer = observer;
this.monitor = monitor;
@@ -147,5 +158,6 @@
this.isSystemRestore = isSystemRestore;
this.filterSet = filterSet;
this.listener = listener;
+ this.backupEligibilityRules = backupEligibilityRules;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 5a57cdc..3102b5f 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -42,6 +42,7 @@
import com.android.server.backup.params.RestoreGetSetsParams;
import com.android.server.backup.params.RestoreParams;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import java.util.function.BiFunction;
@@ -55,6 +56,7 @@
private final String mTransportName;
private final UserBackupManagerService mBackupManagerService;
private final int mUserId;
+ private final BackupEligibilityRules mBackupEligibilityRules;
@Nullable private final String mPackageName;
public RestoreSet[] mRestoreSets = null;
boolean mEnded = false;
@@ -63,12 +65,14 @@
public ActiveRestoreSession(
UserBackupManagerService backupManagerService,
@Nullable String packageName,
- String transportName) {
+ String transportName,
+ BackupEligibilityRules backupEligibilityRules) {
mBackupManagerService = backupManagerService;
mPackageName = packageName;
mTransportManager = backupManagerService.getTransportManager();
mTransportName = transportName;
mUserId = backupManagerService.getUserId();
+ mBackupEligibilityRules = backupEligibilityRules;
}
public void markTimedOut() {
@@ -178,7 +182,8 @@
observer,
monitor,
token,
- listener),
+ listener,
+ mBackupEligibilityRules),
"RestoreSession.restoreAll()");
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -271,7 +276,8 @@
token,
packages,
/* isSystemRestore */ packages.length > 1,
- listener),
+ listener,
+ mBackupEligibilityRules),
"RestoreSession.restorePackages(" + packages.length + " packages)");
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -363,7 +369,8 @@
monitor,
token,
app,
- listener),
+ listener,
+ mBackupEligibilityRules),
"RestoreSession.restorePackage(" + packageName + ")");
} finally {
Binder.restoreCallingIdentity(oldId);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 1f85d10..1c93d4e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -48,6 +48,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
+import android.net.DnsResolver;
import android.net.INetworkManagementEventObserver;
import android.net.Ikev2VpnProfile;
import android.net.IpPrefix;
@@ -79,6 +80,7 @@
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -123,6 +125,7 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
@@ -134,6 +137,8 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -190,6 +195,7 @@
// automated reconnection
private final Context mContext;
+ @VisibleForTesting final Dependencies mDeps;
private final NetworkInfo mNetworkInfo;
@VisibleForTesting protected String mPackage;
private int mOwnerUID;
@@ -252,17 +258,143 @@
// Handle of the user initiating VPN.
private final int mUserHandle;
+ interface RetryScheduler {
+ void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException;
+ }
+
+ static class Dependencies {
+ public void startService(final String serviceName) {
+ SystemService.start(serviceName);
+ }
+
+ public void stopService(final String serviceName) {
+ SystemService.stop(serviceName);
+ }
+
+ public boolean isServiceRunning(final String serviceName) {
+ return SystemService.isRunning(serviceName);
+ }
+
+ public boolean isServiceStopped(final String serviceName) {
+ return SystemService.isStopped(serviceName);
+ }
+
+ public File getStateFile() {
+ return new File("/data/misc/vpn/state");
+ }
+
+ public void sendArgumentsToDaemon(
+ final String daemon, final LocalSocket socket, final String[] arguments,
+ final RetryScheduler retryScheduler) throws IOException, InterruptedException {
+ final LocalSocketAddress address = new LocalSocketAddress(
+ daemon, LocalSocketAddress.Namespace.RESERVED);
+
+ // Wait for the socket to connect.
+ while (true) {
+ try {
+ socket.connect(address);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ retryScheduler.checkInterruptAndDelay(true /* sleepLonger */);
+ }
+ socket.setSoTimeout(500);
+
+ final OutputStream out = socket.getOutputStream();
+ for (String argument : arguments) {
+ byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
+ if (bytes.length >= 0xFFFF) {
+ throw new IllegalArgumentException("Argument is too large");
+ }
+ out.write(bytes.length >> 8);
+ out.write(bytes.length);
+ out.write(bytes);
+ retryScheduler.checkInterruptAndDelay(false /* sleepLonger */);
+ }
+ out.write(0xFF);
+ out.write(0xFF);
+
+ // Wait for End-of-File.
+ final InputStream in = socket.getInputStream();
+ while (true) {
+ try {
+ if (in.read() == -1) {
+ break;
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ retryScheduler.checkInterruptAndDelay(true /* sleepLonger */);
+ }
+ }
+
+ @NonNull
+ public InetAddress resolve(final String endpoint)
+ throws ExecutionException, InterruptedException {
+ try {
+ return InetAddress.parseNumericAddress(endpoint);
+ } catch (IllegalArgumentException e) {
+ // Endpoint is not numeric : fall through and resolve
+ }
+
+ final CancellationSignal cancellationSignal = new CancellationSignal();
+ try {
+ final DnsResolver resolver = DnsResolver.getInstance();
+ final CompletableFuture<InetAddress> result = new CompletableFuture();
+ final DnsResolver.Callback<List<InetAddress>> cb =
+ new DnsResolver.Callback<List<InetAddress>>() {
+ @Override
+ public void onAnswer(@NonNull final List<InetAddress> answer,
+ final int rcode) {
+ if (answer.size() > 0) {
+ result.complete(answer.get(0));
+ } else {
+ result.completeExceptionally(
+ new UnknownHostException(endpoint));
+ }
+ }
+
+ @Override
+ public void onError(@Nullable final DnsResolver.DnsException error) {
+ // Unfortunately UnknownHostException doesn't accept a cause, so
+ // print a message here instead. Only show the summary, not the
+ // full stack trace.
+ Log.e(TAG, "Async dns resolver error : " + error);
+ result.completeExceptionally(new UnknownHostException(endpoint));
+ }
+ };
+ resolver.query(null /* network, null for default */, endpoint,
+ DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb);
+ return result.get();
+ } catch (final ExecutionException e) {
+ Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e);
+ throw e;
+ } catch (final InterruptedException e) {
+ Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e);
+ cancellationSignal.cancel();
+ throw e;
+ }
+ }
+
+ public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ return vpn.jniCheck(iface) == 0;
+ }
+ }
+
public Vpn(Looper looper, Context context, INetworkManagementService netService,
@UserIdInt int userHandle, @NonNull KeyStore keyStore) {
- this(looper, context, netService, userHandle, keyStore,
+ this(looper, context, new Dependencies(), netService, userHandle, keyStore,
new SystemServices(context), new Ikev2SessionCreator());
}
@VisibleForTesting
- protected Vpn(Looper looper, Context context, INetworkManagementService netService,
+ protected Vpn(Looper looper, Context context, Dependencies deps,
+ INetworkManagementService netService,
int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
+ mDeps = deps;
mNetd = netService;
mUserHandle = userHandle;
mLooper = looper;
@@ -2129,7 +2261,8 @@
}
/** This class represents the common interface for all VPN runners. */
- private abstract class VpnRunner extends Thread {
+ @VisibleForTesting
+ abstract class VpnRunner extends Thread {
protected VpnRunner(String name) {
super(name);
@@ -2638,7 +2771,7 @@
} catch (InterruptedException e) {
}
for (String daemon : mDaemons) {
- SystemService.stop(daemon);
+ mDeps.stopService(daemon);
}
}
agentDisconnect();
@@ -2655,21 +2788,55 @@
}
}
+ private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) {
+ final String endpointAddressString = endpointAddress.getHostAddress();
+ // Perform some safety checks before inserting the address in place.
+ // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd.
+ if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) {
+ throw new IllegalStateException("Unexpected daemons order");
+ }
+
+ // Respectively, the positions at which racoon and mtpd take the server address
+ // argument are 1 and 2. Not all types of VPN require both daemons however, and
+ // in that case the corresponding argument array is null.
+ if (mArguments[0] != null) {
+ if (!mProfile.server.equals(mArguments[0][1])) {
+ throw new IllegalStateException("Invalid server argument for racoon");
+ }
+ mArguments[0][1] = endpointAddressString;
+ }
+
+ if (mArguments[1] != null) {
+ if (!mProfile.server.equals(mArguments[1][2])) {
+ throw new IllegalStateException("Invalid server argument for mtpd");
+ }
+ mArguments[1][2] = endpointAddressString;
+ }
+ }
+
private void bringup() {
// Catch all exceptions so we can clean up a few things.
try {
+ // resolve never returns null. If it does because of some bug, it will be
+ // caught by the catch() block below and cleanup gracefully.
+ final InetAddress endpointAddress = mDeps.resolve(mProfile.server);
+
+ // Big hack : dynamically replace the address of the server in the arguments
+ // with the resolved address.
+ checkAndFixupArguments(endpointAddress);
+
// Initialize the timer.
mBringupStartTime = SystemClock.elapsedRealtime();
// Wait for the daemons to stop.
for (String daemon : mDaemons) {
- while (!SystemService.isStopped(daemon)) {
+ while (!mDeps.isServiceStopped(daemon)) {
checkInterruptAndDelay(true);
}
}
// Clear the previous state.
- File state = new File("/data/misc/vpn/state");
+ final File state = mDeps.getStateFile();
state.delete();
if (state.exists()) {
throw new IllegalStateException("Cannot delete the state");
@@ -2696,57 +2863,19 @@
// Start the daemon.
String daemon = mDaemons[i];
- SystemService.start(daemon);
+ mDeps.startService(daemon);
// Wait for the daemon to start.
- while (!SystemService.isRunning(daemon)) {
+ while (!mDeps.isServiceRunning(daemon)) {
checkInterruptAndDelay(true);
}
// Create the control socket.
mSockets[i] = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(
- daemon, LocalSocketAddress.Namespace.RESERVED);
- // Wait for the socket to connect.
- while (true) {
- try {
- mSockets[i].connect(address);
- break;
- } catch (Exception e) {
- // ignore
- }
- checkInterruptAndDelay(true);
- }
- mSockets[i].setSoTimeout(500);
-
- // Send over the arguments.
- OutputStream out = mSockets[i].getOutputStream();
- for (String argument : arguments) {
- byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
- if (bytes.length >= 0xFFFF) {
- throw new IllegalArgumentException("Argument is too large");
- }
- out.write(bytes.length >> 8);
- out.write(bytes.length);
- out.write(bytes);
- checkInterruptAndDelay(false);
- }
- out.write(0xFF);
- out.write(0xFF);
-
- // Wait for End-of-File.
- InputStream in = mSockets[i].getInputStream();
- while (true) {
- try {
- if (in.read() == -1) {
- break;
- }
- } catch (Exception e) {
- // ignore
- }
- checkInterruptAndDelay(true);
- }
+ // Wait for the socket to connect and send over the arguments.
+ mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments,
+ this::checkInterruptAndDelay);
}
// Wait for the daemons to create the new state.
@@ -2754,7 +2883,7 @@
// Check if a running daemon is dead.
for (int i = 0; i < mDaemons.length; ++i) {
String daemon = mDaemons[i];
- if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
+ if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) {
throw new IllegalStateException(daemon + " is dead");
}
}
@@ -2764,7 +2893,8 @@
// Now we are connected. Read and parse the new state.
String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
if (parameters.length != 7) {
- throw new IllegalStateException("Cannot parse the state");
+ throw new IllegalStateException("Cannot parse the state: '"
+ + String.join("', '", parameters) + "'");
}
// Set the interface and the addresses in the config.
@@ -2793,20 +2923,15 @@
}
// Add a throw route for the VPN server endpoint, if one was specified.
- String endpoint = parameters[5].isEmpty() ? mProfile.server : parameters[5];
- if (!endpoint.isEmpty()) {
- try {
- InetAddress addr = InetAddress.parseNumericAddress(endpoint);
- if (addr instanceof Inet4Address) {
- mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW));
- } else if (addr instanceof Inet6Address) {
- mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW));
- } else {
- Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint);
- }
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e);
- }
+ if (endpointAddress instanceof Inet4Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 32), RTN_THROW));
+ } else if (endpointAddress instanceof Inet6Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 128), RTN_THROW));
+ } else {
+ Log.e(TAG, "Unknown IP address family for VPN endpoint: "
+ + endpointAddress);
}
// Here is the last step and it must be done synchronously.
@@ -2818,7 +2943,7 @@
checkInterruptAndDelay(false);
// Check if the interface is gone while we are waiting.
- if (jniCheck(mConfig.interfaze) == 0) {
+ if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) {
throw new IllegalStateException(mConfig.interfaze + " is gone");
}
@@ -2849,7 +2974,7 @@
while (true) {
Thread.sleep(2000);
for (int i = 0; i < mDaemons.length; i++) {
- if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
+ if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) {
return;
}
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 0eaac41..9646b9c 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -52,6 +52,7 @@
import com.android.internal.util.XmlUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import libcore.io.IoUtils;
import libcore.util.HexEncoding;
@@ -112,6 +113,7 @@
private static final String ATTR_GRANTED = "granted";
private final PackageManagerService mService;
+ private final PermissionManagerServiceInternal mPermissionManager;
private final CookiePersistence mCookiePersistence;
/** State for uninstalled instant apps */
@@ -131,8 +133,10 @@
@GuardedBy("mService.mLock")
private SparseArray<SparseBooleanArray> mInstalledInstantAppUids;
- public InstantAppRegistry(PackageManagerService service) {
+ public InstantAppRegistry(PackageManagerService service,
+ PermissionManagerServiceInternal permissionManager) {
mService = service;
+ mPermissionManager = permissionManager;
mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
}
@@ -861,7 +865,8 @@
String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()];
pkg.getRequestedPermissions().toArray(requestedPermissions);
- Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
+ Set<String> permissions = mPermissionManager.getGrantedPermissions(
+ pkg.getPackageName(), userId);
String[] grantedPermissions = new String[permissions.size()];
permissions.toArray(grantedPermissions);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 58a1648..997c7e3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2970,7 +2970,7 @@
mHandler = new PackageHandler(mHandlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
- mInstantAppRegistry = new InstantAppRegistry(this);
+ mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
= systemConfig.getSharedLibraries();
@@ -4385,14 +4385,13 @@
final PackageUserState state = ps.readUserState(userId);
AndroidPackage p = ps.pkg;
if (p != null) {
- final PermissionsState permissionsState = ps.getPermissionsState();
-
// Compute GIDs only if requested
final int[] gids = (flags & PackageManager.GET_GIDS) == 0
- ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
+ ? EMPTY_INT_ARRAY : mPermissionManager.getPackageGids(ps.name, userId);
// Compute granted permissions only if package has requested permissions
final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
- ? Collections.emptySet() : permissionsState.getPermissions(userId);
+ ? Collections.emptySet()
+ : mPermissionManager.getGrantedPermissions(ps.name, userId);
PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
@@ -4863,13 +4862,13 @@
}
// TODO: Shouldn't this be checking for package installed state for userId and
// return null?
- return ps.getPermissionsState().computeGids(userId);
+ return mPermissionManager.getPackageGids(packageName, userId);
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
- return ps.getPermissionsState().computeGids(userId);
+ return mPermissionManager.getPackageGids(packageName, userId);
}
}
}
@@ -24948,9 +24947,7 @@
@Override
public int[] getPermissionGids(String permissionName, int userId) {
- synchronized (mLock) {
- return getPermissionGidsLocked(permissionName, userId);
- }
+ return mPermissionManager.getPermissionGids(permissionName, userId);
}
@Override
@@ -25271,16 +25268,6 @@
return null;
}
- @GuardedBy("mLock")
- public int[] getPermissionGidsLocked(String permissionName, int userId) {
- BasePermission perm
- = mPermissionManager.getPermissionSettings().getPermission(permissionName);
- if (perm != null) {
- return perm.computeGids(userId);
- }
- return null;
- }
-
@Override
public int getRuntimePermissionsVersion(@UserIdInt int userId) {
Preconditions.checkArgumentNonnegative(userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index be93b8f..03771be 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2454,6 +2454,36 @@
}
}
+ @NonNull
+ private Set<String> getGrantedPermissions(@NonNull String packageName,
+ @UserIdInt int userId) {
+ final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
+ if (ps == null) {
+ return null;
+ }
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ return permissionsState.getPermissions(userId);
+ }
+
+ @Nullable
+ private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
+ BasePermission permission = mSettings.getPermission(permissionName);
+ if (permission == null) {
+ return null;
+ }
+ return permission.computeGids(userId);
+ }
+
+ @Nullable
+ private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
+ final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
+ if (ps == null) {
+ return null;
+ }
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ return permissionsState.computeGids(userId);
+ }
+
/**
* Restore the permission state for a package.
*
@@ -4650,6 +4680,22 @@
public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
+ @NonNull
+ @Override
+ public Set<String> getGrantedPermissions(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return PermissionManagerService.this.getGrantedPermissions(packageName, userId);
+ }
+ @Nullable
+ @Override
+ public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
+ return PermissionManagerService.this.getPermissionGids(permissionName, userId);
+ }
+ @Nullable
+ @Override
+ public int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
+ return PermissionManagerService.this.getPackageGids(packageName, userId);
+ }
@Override
public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
String[] grantedPermissions, int callingUid) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 2e83b23..cfa371d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.function.Consumer;
/**
@@ -263,6 +264,25 @@
public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+ /**
+ * Get all the permissions granted to a package.
+ */
+ @NonNull
+ public abstract Set<String> getGrantedPermissions(@NonNull String packageName,
+ @UserIdInt int userId);
+
+ /**
+ * Get the GIDs of a permission.
+ */
+ @Nullable
+ public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId);
+
+ /**
+ * Get the GIDs computed from the permission state of a package.
+ */
+ @Nullable
+ public abstract int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId);
+
/** Retrieve the packages that have requested the given app op permission */
public abstract @Nullable String[] getAppOpPermissionPackages(
@NonNull String permName, int callingUid);
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 37bf664..33317a3 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.people.ConversationChannel;
+import android.app.people.IPeopleManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionSessionId;
import android.app.prediction.AppTarget;
@@ -26,8 +28,11 @@
import android.app.prediction.IPredictionCallback;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
@@ -35,6 +40,7 @@
import com.android.server.SystemService;
import com.android.server.people.data.DataManager;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -68,6 +74,7 @@
@Override
public void onStart() {
+ publishBinderService(Context.PEOPLE_SERVICE, new BinderService());
publishLocalService(PeopleServiceInternal.class, new LocalService());
}
@@ -81,6 +88,38 @@
mDataManager.onUserStopping(user.getUserIdentifier());
}
+ /**
+ * Enforces that only the system or root UID can make certain calls.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ private static void enforceSystemOrRoot(String message) {
+ int uid = Binder.getCallingUid();
+ if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+ throw new SecurityException("Only system may " + message);
+ }
+ }
+
+ private final class BinderService extends IPeopleManager.Stub {
+
+ @Override
+ public ParceledListSlice<ConversationChannel> getRecentConversations() {
+ enforceSystemOrRoot("get recent conversations");
+ return new ParceledListSlice<>(new ArrayList<>());
+ }
+
+ @Override
+ public void removeRecentConversation(String packageName, int userId, String shortcutId) {
+ enforceSystemOrRoot("remove a recent conversation");
+ }
+
+ @Override
+ public void removeAllRecentConversations() {
+ enforceSystemOrRoot("remove all recent conversations");
+ }
+ }
+
@VisibleForTesting
final class LocalService extends PeopleServiceInternal {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index cd9b6ac..cbebe69 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -1092,9 +1092,11 @@
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
+ backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
- verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+ verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
}
/** Test that the backup service does not route methods for non-registered users. */
@@ -1104,9 +1106,11 @@
registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
+ backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
- verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+ verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
+ OperationType.BACKUP);
}
/** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 3fc421d..5883c1c 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -57,6 +57,7 @@
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowEventLog;
import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask;
@@ -96,6 +97,7 @@
@Mock private TransportManager mTransportManager;
@Mock private IRestoreObserver mObserver;
@Mock private IBackupManagerMonitor mMonitor;
+ @Mock private BackupEligibilityRules mBackupEligibilityRules;
private ShadowLooper mShadowBackupLooper;
private ShadowApplication mShadowApplication;
private UserBackupManagerService.BackupWakeLock mWakeLock;
@@ -576,7 +578,8 @@
private IRestoreSession createActiveRestoreSession(
String packageName, TransportData transport) {
return new ActiveRestoreSession(
- mBackupManagerService, packageName, transport.transportName);
+ mBackupManagerService, packageName, transport.transportName,
+ mBackupEligibilityRules);
}
private IRestoreSession createActiveRestoreSessionWithRestoreSets(
@@ -584,7 +587,8 @@
throws RemoteException {
ActiveRestoreSession restoreSession =
new ActiveRestoreSession(
- mBackupManagerService, packageName, transport.transportName);
+ mBackupManagerService, packageName, transport.transportName,
+ mBackupEligibilityRules);
restoreSession.setRestoreSets(restoreSets);
return restoreSession;
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
index bc478b0..207f10a 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -104,8 +104,11 @@
}
private val tempFolder = TemporaryFolder()
+
+ // TODO(b/160159215): Use START_STOP rather than FULL once it's fixed. This will drastically
+ // improve pre/post-submit times.
private val preparer: SystemPreparer = SystemPreparer(tempFolder,
- SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device }
+ SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
@get:Rule
val rules = RuleChain.outerRule(tempFolder).let {
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 4ccf79a..de1c5759 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -30,6 +30,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -49,6 +50,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -65,6 +67,7 @@
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.LinkProperties;
+import android.net.LocalSocket;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
@@ -74,6 +77,7 @@
import android.net.VpnService;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.ConditionVariable;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Process;
@@ -101,13 +105,20 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.net.Inet4Address;
+import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
/**
@@ -133,7 +144,8 @@
managedProfileA.profileGroupId = primaryUser.id;
}
- static final String TEST_VPN_PKG = "com.dummy.vpn";
+ static final String EGRESS_IFACE = "wlan0";
+ static final String TEST_VPN_PKG = "com.testvpn.vpn";
private static final String TEST_VPN_SERVER = "1.2.3.4";
private static final String TEST_VPN_IDENTITY = "identity";
private static final byte[] TEST_VPN_PSK = "psk".getBytes();
@@ -1012,31 +1024,190 @@
// a subsequent CL.
}
- @Test
- public void testStartLegacyVpn() throws Exception {
+ public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
// Dummy egress interface
- final String egressIface = "DUMMY0";
final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(egressIface);
+ lp.setInterfaceName(EGRESS_IFACE);
final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
- InetAddresses.parseNumericAddress("192.0.2.0"), egressIface);
+ InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
lp.addRoute(defaultRoute);
- vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp);
+ vpn.startLegacyVpn(vpnProfile, mKeyStore, lp);
+ return vpn;
+ }
+ @Test
+ public void testStartPlatformVpn() throws Exception {
+ startLegacyVpn(mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent CL.
+ // a subsequent patch.
+ }
+
+ @Test
+ public void testStartRacoonNumericAddress() throws Exception {
+ startRacoon("1.2.3.4", "1.2.3.4");
+ }
+
+ @Test
+ public void testStartRacoonHostname() throws Exception {
+ startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
+ }
+
+ public void startRacoon(final String serverAddr, final String expectedAddr)
+ throws Exception {
+ final ConditionVariable legacyRunnerReady = new ConditionVariable();
+ final VpnProfile profile = new VpnProfile("testProfile" /* key */);
+ profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
+ profile.name = "testProfileName";
+ profile.username = "userName";
+ profile.password = "thePassword";
+ profile.server = serverAddr;
+ profile.ipsecIdentifier = "id";
+ profile.ipsecSecret = "secret";
+ profile.l2tpSecret = "l2tpsecret";
+ when(mConnectivityManager.getAllNetworks())
+ .thenReturn(new Network[] { new Network(101) });
+ when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
+ anyInt(), any(), anyInt())).thenAnswer(invocation -> {
+ // The runner has registered an agent and is now ready.
+ legacyRunnerReady.open();
+ return new Network(102);
+ });
+ final Vpn vpn = startLegacyVpn(profile);
+ final TestDeps deps = (TestDeps) vpn.mDeps;
+ try {
+ // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
+ assertArrayEquals(
+ new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
+ profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
+ deps.racoonArgs.get(10, TimeUnit.SECONDS));
+ // literal values are hardcoded in Vpn.java for mtpd args
+ assertArrayEquals(
+ new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
+ "idle", "1800", "mtu", "1400", "mru", "1400" },
+ deps.mtpdArgs.get(10, TimeUnit.SECONDS));
+ // Now wait for the runner to be ready before testing for the route.
+ legacyRunnerReady.block(10_000);
+ // In this test the expected address is always v4 so /32
+ final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
+ RouteInfo.RTN_THROW);
+ assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : "
+ + vpn.mConfig.routes,
+ vpn.mConfig.routes.contains(expectedRoute));
+ } finally {
+ // Now interrupt the thread, unblock the runner and clean up.
+ vpn.mVpnRunner.exitVpnRunner();
+ deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
+ vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
+ }
+ }
+
+ private static final class TestDeps extends Vpn.Dependencies {
+ public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
+ public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
+ public final File mStateFile;
+
+ private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
+
+ TestDeps() {
+ try {
+ mStateFile = File.createTempFile("vpnTest", ".tmp");
+ mStateFile.deleteOnExit();
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void startService(final String serviceName) {
+ mRunningServices.put(serviceName, true);
+ }
+
+ @Override
+ public void stopService(final String serviceName) {
+ mRunningServices.put(serviceName, false);
+ }
+
+ @Override
+ public boolean isServiceRunning(final String serviceName) {
+ return mRunningServices.getOrDefault(serviceName, false);
+ }
+
+ @Override
+ public boolean isServiceStopped(final String serviceName) {
+ return !isServiceRunning(serviceName);
+ }
+
+ @Override
+ public File getStateFile() {
+ return mStateFile;
+ }
+
+ @Override
+ public void sendArgumentsToDaemon(
+ final String daemon, final LocalSocket socket, final String[] arguments,
+ final Vpn.RetryScheduler interruptChecker) throws IOException {
+ if ("racoon".equals(daemon)) {
+ racoonArgs.complete(arguments);
+ } else if ("mtpd".equals(daemon)) {
+ writeStateFile(arguments);
+ mtpdArgs.complete(arguments);
+ } else {
+ throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
+ }
+ }
+
+ private void writeStateFile(final String[] arguments) throws IOException {
+ mStateFile.delete();
+ mStateFile.createNewFile();
+ mStateFile.deleteOnExit();
+ final BufferedWriter writer = new BufferedWriter(
+ new FileWriter(mStateFile, false /* append */));
+ writer.write(EGRESS_IFACE);
+ writer.write("\n");
+ // addresses
+ writer.write("10.0.0.1/24\n");
+ // routes
+ writer.write("192.168.6.0/24\n");
+ // dns servers
+ writer.write("192.168.6.1\n");
+ // search domains
+ writer.write("vpn.searchdomains.com\n");
+ // endpoint - intentionally empty
+ writer.write("\n");
+ writer.flush();
+ writer.close();
+ }
+
+ @Override
+ @NonNull
+ public InetAddress resolve(final String endpoint) {
+ try {
+ // If a numeric IP address, return it.
+ return InetAddress.parseNumericAddress(endpoint);
+ } catch (IllegalArgumentException e) {
+ // Otherwise, return some token IP to test for.
+ return InetAddress.parseNumericAddress("5.6.7.8");
+ }
+ }
+
+ @Override
+ public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ return true;
+ }
}
/**
* Mock some methods of vpn object.
*/
private Vpn createVpn(@UserIdInt int userId) {
- return new Vpn(Looper.myLooper(), mContext, mNetService,
+ return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
}