diff options
| author | 2016-03-18 23:04:56 +0000 | |
|---|---|---|
| committer | 2016-03-18 23:04:58 +0000 | |
| commit | a46f1f7060c5212c7533cb0db3f8442f211e20eb (patch) | |
| tree | 4c4130b3078157da32806b1a503e29bdc7f89dac | |
| parent | 9bc6ba974608592df72b2456e7dfa285741364ea (diff) | |
| parent | c7354fe2d4d73808929d2087f2d18ee3d8fa47fc (diff) | |
Merge "Notify VrListenerService when VR activity changes." into nyc-dev
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/service/vr/IVrListener.aidl | 6 | ||||
| -rw-r--r-- | core/java/android/service/vr/VrListenerService.java | 49 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/utils/ManagedApplicationService.java | 45 | ||||
| -rw-r--r-- | services/core/java/com/android/server/vr/VrManagerInternal.java | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/vr/VrManagerService.java | 78 |
9 files changed, 151 insertions, 37 deletions
diff --git a/api/current.txt b/api/current.txt index a66aac37838b..5577c8b29582 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35022,6 +35022,7 @@ package android.service.vr { 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 676dd38c5d65..78d50d4803d6 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -37565,6 +37565,7 @@ package android.service.vr { 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 879f4673ba6d..5acbbb9420d8 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -35093,6 +35093,7 @@ package android.service.vr { 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 b7273ba91187..afb13d316503 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 5f1f659710a7..9a5e95d7a4bd 100644 --- a/core/java/android/service/vr/VrListenerService.java +++ b/core/java/android/service/vr/VrListenerService.java @@ -23,7 +23,10 @@ import android.app.Service; 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 @@ public abstract class VrListenerService extends Service { @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 4f0f7704f0b8..fc74623900da 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 a64570130e45..ad8acef0c12a 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 @@ public class ManagedApplicationService { private ServiceConnection mPendingConnection; private ServiceConnection mConnection; private IInterface mBoundInterface; + private PendingEvent mPendingEvent; + private ManagedApplicationService(final Context context, final ComponentName component, @@ -82,6 +84,13 @@ public class ManagedApplicationService { } /** + * 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 @@ public class ManagedApplicationService { 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 @@ public class ManagedApplicationService { 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 @@ public class ManagedApplicationService { 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 6b5523f0510b..8316efa7eb4c 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 @@ public abstract class VrManagerInternal { * @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 d0ee6e030c09..0aa30526ed2e 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.app.AppOpsManager; 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 android.util.Slog; 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 @@ public class VrManagerService extends SystemService implements EnabledComponentC 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 @@ public class VrManagerService extends SystemService implements EnabledComponentC // There is an active service, update it if needed updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(), - mCurrentVrService.getUserId()); + mCurrentVrService.getUserId(), null); } } @@ -119,8 +121,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @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 @@ public class VrManagerService extends SystemService implements EnabledComponentC * @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 @@ public class VrManagerService extends SystemService implements EnabledComponentC mCurrentVrService.disconnect(); mCurrentVrService = null; } - return validUserComponent; - } - - 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 " + + } 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; } - // 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 @@ public class VrManagerService extends SystemService implements EnabledComponentC */ 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); } } |