Merge "Don't bind ChooserTargetServices as user CURRENT" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index a66aac3..5577c8b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35022,6 +35022,7 @@
ctor public VrListenerService();
method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
+ method public void onCurrentVrActivityChanged(android.content.ComponentName);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 676dd38..78d50d4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37565,6 +37565,7 @@
ctor public VrListenerService();
method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
+ method public void onCurrentVrActivityChanged(android.content.ComponentName);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 879f467..5acbbb9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35093,6 +35093,7 @@
ctor public VrListenerService();
method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
+ method public void onCurrentVrActivityChanged(android.content.ComponentName);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
}
diff --git a/core/java/android/service/vr/IVrListener.aidl b/core/java/android/service/vr/IVrListener.aidl
index b7273ba..afb13d3 100644
--- a/core/java/android/service/vr/IVrListener.aidl
+++ b/core/java/android/service/vr/IVrListener.aidl
@@ -16,7 +16,9 @@
package android.service.vr;
+import android.content.ComponentName;
+
/** @hide */
oneway interface IVrListener {
-
-}
\ No newline at end of file
+ void focusedActivityChanged(in ComponentName component);
+}
diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java
index 5f1f659..9a5e95d 100644
--- a/core/java/android/service/vr/VrListenerService.java
+++ b/core/java/android/service/vr/VrListenerService.java
@@ -23,7 +23,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
/**
* A service that is bound from the system while running in virtual reality (VR) mode.
@@ -55,19 +58,53 @@
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
- /**
- * @hide
- */
- public static class VrListenerBinder extends IVrListener.Stub {
- }
+ private final Handler mHandler;
- private final VrListenerBinder mBinder = new VrListenerBinder();
+ private static final int MSG_ON_CURRENT_VR_ACTIVITY_CHANGED = 1;
+
+ private final IVrListener.Stub mBinder = new IVrListener.Stub() {
+ @Override
+ public void focusedActivityChanged(ComponentName component) {
+ mHandler.obtainMessage(MSG_ON_CURRENT_VR_ACTIVITY_CHANGED, component).sendToTarget();
+ }
+ };
+
+ private final class VrListenerHandler extends Handler {
+ public VrListenerHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_CURRENT_VR_ACTIVITY_CHANGED: {
+ VrListenerService.this.onCurrentVrActivityChanged((ComponentName) msg.obj);
+ } break;
+ }
+ }
+ }
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
+ public VrListenerService() {
+ mHandler = new VrListenerHandler(Looper.getMainLooper());
+ }
+
+ /**
+ * Called when the current activity using VR mode is changed.
+ * <p/>
+ * This will be called immediately when this service is initially bound, but is
+ * not guaranteed to be called before onUnbind.
+ *
+ * @param component the {@link ComponentName} of the new current VR activity.
+ */
+ public void onCurrentVrActivityChanged(ComponentName component) {
+ // Override to implement
+ }
+
/**
* Check if the given package is available to be enabled/disabled in VR mode settings.
*
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4f0f770..fc74623 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2168,17 +2168,19 @@
final ActivityRecord r = (ActivityRecord) msg.obj;
boolean vrMode;
ComponentName requestedPackage;
+ ComponentName callingPackage;
int userId;
synchronized (ActivityManagerService.this) {
vrMode = r.requestedVrComponent != null;
requestedPackage = r.requestedVrComponent;
userId = r.userId;
+ callingPackage = r.info.getComponentName();
if (mInVrMode != vrMode) {
mInVrMode = vrMode;
mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
}
}
- vrService.setVrMode(vrMode, requestedPackage, userId);
+ vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
} break;
}
}
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index a645701..ad8acef0 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -60,6 +60,8 @@
private ServiceConnection mPendingConnection;
private ServiceConnection mConnection;
private IInterface mBoundInterface;
+ private PendingEvent mPendingEvent;
+
private ManagedApplicationService(final Context context, final ComponentName component,
@@ -82,6 +84,13 @@
}
/**
+ * Implement to call IInterface methods after service is connected.
+ */
+ public interface PendingEvent {
+ void runEvent(IInterface service) throws RemoteException;
+ }
+
+ /**
* Create a new ManagedApplicationService object but do not yet bind to the user service.
*
* @param context a Context to use for binding the application service.
@@ -131,6 +140,30 @@
return true;
}
+
+ /**
+ * Send an event to run as soon as the binder interface is available.
+ *
+ * @param event a {@link PendingEvent} to send.
+ */
+ public void sendEvent(@NonNull PendingEvent event) {
+ IInterface iface;
+ synchronized (mLock) {
+ iface = mBoundInterface;
+ if (iface == null) {
+ mPendingEvent = event;
+ }
+ }
+
+ if (iface != null) {
+ try {
+ event.runEvent(iface);
+ } catch (RuntimeException | RemoteException ex) {
+ Slog.e(TAG, "Received exception from user service: ", ex);
+ }
+ }
+ }
+
/**
* Asynchronously unbind from the application service if bound.
*/
@@ -168,6 +201,8 @@
final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ IInterface iface = null;
+ PendingEvent pendingEvent = null;
synchronized (mLock) {
if (mPendingConnection == this) {
// No longer pending, remove from pending connection
@@ -186,12 +221,22 @@
mContext.unbindService(this);
mBoundInterface = null;
}
+ iface = mBoundInterface;
+ pendingEvent = mPendingEvent;
+ mPendingEvent = null;
} catch (RemoteException e) {
// DOA
Slog.w(TAG, "Unable to bind service: " + intent, e);
mBoundInterface = null;
}
}
+ if (iface != null && pendingEvent != null) {
+ try {
+ pendingEvent.runEvent(iface);
+ } catch (RuntimeException | RemoteException ex) {
+ Slog.e(TAG, "Received exception from user service: ", ex);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 6b5523f..8316efa 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -43,9 +43,10 @@
* @param enabled {@code true} to enable VR mode.
* @param packageName The package name of the requested VrListenerService to bind.
* @param userId the user requesting the VrListenerService component.
+ * @param calling the component currently using VR mode, or null to leave unchanged.
*/
public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
- int userId);
+ int userId, @NonNull ComponentName calling);
/**
* Add a listener for VR mode state changes.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index d0ee6e0..0aa3052 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -19,14 +19,12 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
-import android.os.UserHandle;
+import android.os.RemoteException;
import android.provider.Settings;
import android.service.vr.IVrListener;
import android.service.vr.VrListenerService;
@@ -35,11 +33,13 @@
import com.android.internal.R;
import com.android.server.SystemService;
+import com.android.server.utils.ManagedApplicationService.PendingEvent;
import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.Set;
/**
@@ -79,6 +79,8 @@
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private Context mContext;
+ private ComponentName mCurrentVrModeComponent;
+ private int mCurrentVrModeUser;
private static final BinderChecker sBinderChecker = new BinderChecker() {
@Override
@@ -105,7 +107,7 @@
// There is an active service, update it if needed
updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
- mCurrentVrService.getUserId());
+ mCurrentVrService.getUserId(), null);
}
}
@@ -119,8 +121,9 @@
}
@Override
- public void setVrMode(boolean enabled, ComponentName packageName, int userId) {
- VrManagerService.this.setVrMode(enabled, packageName, userId);
+ public void setVrMode(boolean enabled, ComponentName packageName, int userId,
+ ComponentName callingPackage) {
+ VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
}
@Override
@@ -227,11 +230,14 @@
* @param enabled new state for VR mode.
* @param component new component to be bound as a VR listener.
* @param userId user owning the component to be bound.
+ * @param calling the component currently using VR mode, or null to leave unchanged.
*
* @return {@code true} if the component/user combination specified is valid.
*/
private boolean updateCurrentVrServiceLocked(boolean enabled,
- @NonNull ComponentName component, int userId) {
+ @NonNull ComponentName component, int userId, ComponentName calling) {
+
+ boolean sendUpdatedCaller = false;
boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
EnabledComponentsObserver.NO_ERROR);
@@ -247,31 +253,49 @@
mCurrentVrService.disconnect();
mCurrentVrService = null;
}
- return validUserComponent;
+ } else {
+ if (mCurrentVrService != null) {
+ // Unbind any running service that doesn't match the component/user selection
+ if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
+ mCurrentVrService.getUserId());
+ createAndConnectService(component, userId);
+ sendUpdatedCaller = true;
+ }
+ // The service with the correct component/user is bound
+ } else {
+ // Nothing was previously running, bind a new service
+ createAndConnectService(component, userId);
+ sendUpdatedCaller = true;
+ }
}
- if (mCurrentVrService != null) {
- // Unbind any running service that doesn't match the component/user selection
- if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
- Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
- mCurrentVrService = VrManagerService.create(mContext, component, userId);
- mCurrentVrService.connect();
- Slog.i(TAG, "Connecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
- }
- // The service with the correct component/user is bound
- } else {
- // Nothing was previously running, bind a new service
- mCurrentVrService = VrManagerService.create(mContext, component, userId);
- mCurrentVrService.connect();
- Slog.i(TAG, "Connecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
+ if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
+ mCurrentVrModeComponent = calling;
+ mCurrentVrModeUser = userId;
+ sendUpdatedCaller = true;
+ }
+
+ if (mCurrentVrService != null && sendUpdatedCaller) {
+ final ComponentName c = mCurrentVrModeComponent;
+ mCurrentVrService.sendEvent(new PendingEvent() {
+ @Override
+ public void runEvent(IInterface service) throws RemoteException {
+ IVrListener l = (IVrListener) service;
+ l.focusedActivityChanged(c);
+ }
+ });
}
return validUserComponent;
}
+ private void createAndConnectService(@NonNull ComponentName component, int userId) {
+ mCurrentVrService = VrManagerService.create(mContext, component, userId);
+ mCurrentVrService.connect();
+ Slog.i(TAG, "Connecting " + component + " for user " + userId);
+ }
+
/**
* Send VR mode change callbacks to HAL and system services if mode has actually changed.
* <p/>
@@ -319,9 +343,9 @@
*/
private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
- int userId) {
+ int userId, @NonNull ComponentName callingPackage) {
synchronized (mLock) {
- return updateCurrentVrServiceLocked(enabled, targetPackageName, userId);
+ return updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
}
}