Notify VrListenerService when VR activity changes.
Bug: 27536964
Bug: 22855417
Change-Id: I67e1f8e6595332b3d768a99735bbd5fd38dffdc9
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);
}
}