Introduces VrManager as a system service.

Provides access to persistent VR mode as used by VR viewer when a device
is believed to be inside a viewer.

Bug: 34736524
Test: Built, run using build of vr services that enables mode.
Change-Id: I6ff392f09adb8e4bd522dacbd064777bba836282
This commit is contained in:
Zak Cohen
2017-01-26 13:54:28 -08:00
parent 53780b6877
commit 56345f4bfe
7 changed files with 148 additions and 12 deletions

View File

@@ -6204,6 +6204,10 @@ package android.app {
method public void onDetached();
}
public class VrManager {
method public void setPersistentVrModeEnabled(boolean);
}
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -9006,6 +9010,7 @@ package android.content {
field public static final java.lang.String USB_SERVICE = "usb";
field public static final java.lang.String USER_SERVICE = "user";
field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
field public static final java.lang.String VR_SERVICE = "vrmanager";
field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";

View File

@@ -115,6 +115,7 @@ import android.print.PrintManager;
import android.service.autofill.IAutoFillManagerService;
import android.service.persistentdata.IPersistentDataBlockService;
import android.service.persistentdata.PersistentDataBlockManager;
import android.service.vr.IVrManager;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -814,6 +815,14 @@ final class SystemServiceRegistry {
IAutoFillManagerService service = IAutoFillManagerService.Stub.asInterface(b);
return new AutoFillManager(ctx, service);
}});
registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
@Override
public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.VR_SERVICE);
return new VrManager(IVrManager.Stub.asInterface(b));
}
});
}
/**

View File

@@ -0,0 +1,44 @@
package android.app;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.os.RemoteException;
import android.service.vr.IVrManager;
/**
* Used to control aspects of a devices Virtual Reality (VR) capabilities.
* <p>
* You do not instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService}.
* @hide
*/
@SystemApi
public class VrManager {
private final IVrManager mService;
/**
* {@hide}
*/
public VrManager(IVrManager service) {
mService = service;
}
/**
* Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
* remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
* by VR viewers to indicate that a device is placed in a VR viewer.
*
* <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
*
* @see Activity#setVrModeEnabled(boolean, ComponentName)
* @param enabled true if the device should be placed in persistent VR mode.
*/
public void setPersistentVrModeEnabled(boolean enabled) {
try {
mService.setPersistentVrModeEnabled(enabled);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
}

View File

@@ -35,6 +35,7 @@ import android.annotation.UserIdInt;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.Notification;
import android.app.VrManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -3763,6 +3764,16 @@ public abstract class Context {
*/
public static final String OVERLAY_SERVICE = "overlay";
/**
* Use with {@link #getSystemService} to retrieve a
* {@link VrManager} for accessing the VR service.
*
* @see #getSystemService
* @hide
*/
@SystemApi
public static final String VR_SERVICE = "vrmanager";
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.

View File

@@ -42,5 +42,13 @@ interface IVrManager {
*/
boolean getVrModeState();
/**
* Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
* remain in VR mode even if the foreground does not specify VR mode being enabled. Mainly used
* by VR viewers to indicate that a device is placed in a VR viewer.
*
* @param enabled true if the device should be placed in persistent VR mode.
*/
void setPersistentVrModeEnabled(in boolean enabled);
}

View File

@@ -79,4 +79,13 @@ public abstract class VrManagerInternal {
* given in {@link android.service.vr.VrModeException} on failure.
*/
public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
/**
* Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
* remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
* by VR viewers to indicate that a device is placed in a VR viewer.
*
* @param enabled true if the device should be placed in persistent VR mode.
*/
public abstract void setPersistentVrModeEnabled(boolean enabled);
}

View File

@@ -20,15 +20,10 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
@@ -53,7 +48,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -69,8 +63,6 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
@@ -121,8 +113,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
// State protected by mLock
private boolean mVrModeAllowed;
private boolean mVrModeEnabled;
private boolean mPersistentVrModeEnabled;
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private ComponentName mDefaultVrService;
private Context mContext;
private ComponentName mCurrentVrModeComponent;
private int mCurrentVrModeUser;
@@ -157,6 +151,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (mVrModeAllowed) {
consumeAndApplyPendingStateLocked();
} else {
// Disable persistent mode when VR mode isn't allowed, allows an escape hatch to
// exit persistent VR mode when screen is turned off.
mPersistentVrModeEnabled = false;
// Set pending state to current state.
mPendingState = (mVrModeEnabled && mCurrentVrService != null)
? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
@@ -377,6 +375,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return VrManagerService.this.getVrMode();
}
@Override
public void setPersistentVrModeEnabled(boolean enabled) {
enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
VrManagerService.this.setPersistentVrModeEnabled(enabled);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -387,6 +391,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
pw.println("********* Dump of VrManagerService *********");
pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
pw.println("Persistent VR mode is currently: " +
((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
pw.println("Previous state transitions:\n");
String tab = " ";
dumpStateTransitions(pw);
@@ -462,6 +468,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC
public int hasVrPackage(ComponentName packageName, int userId) {
return VrManagerService.this.hasVrPackage(packageName, userId);
}
@Override
public void setPersistentVrModeEnabled(boolean enabled) {
VrManagerService.this.setPersistentVrModeEnabled(enabled);
}
}
public VrManagerService(Context context) {
@@ -494,6 +505,15 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mComponentObserver.rebuildAll();
}
//TODO: something more robust than picking the first one
ArraySet<ComponentName> defaultVrComponents =
SystemConfig.getInstance().getDefaultVrComponents();
if (defaultVrComponents.size() > 0) {
mDefaultVrService = defaultVrComponents.valueAt(0);
} else {
Slog.i(TAG, "No default vr listener service found.");
}
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
mVrModeAllowed = true;
@@ -637,8 +657,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
}
mCurrentVrModeComponent = calling;
if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
mCurrentVrModeComponent = calling;
sendUpdatedCaller = true;
}
@@ -947,7 +967,25 @@ public class VrManagerService extends SystemService implements EnabledComponentC
int userId, @NonNull ComponentName callingPackage) {
synchronized (mLock) {
VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
VrState pending;
ComponentName targetListener;
ComponentName foregroundVrComponent;
// If the device is in persistent VR mode, then calls to disable VR mode are ignored,
// and the system default VR listener is used.
boolean targetEnabledState = enabled || mPersistentVrModeEnabled;
if (!enabled && mPersistentVrModeEnabled) {
targetListener = mDefaultVrService;
// Current foreground component isn't a VR one (in 2D app case)
foregroundVrComponent = null;
} else {
targetListener = targetPackageName;
foregroundVrComponent = callingPackage;
}
pending = new VrState(
targetEnabledState, targetListener, userId, foregroundVrComponent);
if (!mVrModeAllowed) {
// We're not allowed to be in VR mode. Make this state pending. This will be
// applied the next time we are allowed to enter VR mode unless it is superseded by
@@ -956,7 +994,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return;
}
if (!enabled && mCurrentVrService != null) {
if (!targetEnabledState && mCurrentVrService != null) {
// If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
// and service bind/unbind in case we are immediately switching to another VR app.
if (mPendingState == null) {
@@ -971,7 +1009,19 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mPendingState = null;
}
updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
updateCurrentVrServiceLocked(
targetEnabledState, targetListener, userId, foregroundVrComponent);
}
}
private void setPersistentVrModeEnabled(boolean enabled) {
synchronized (mLock) {
mPersistentVrModeEnabled = enabled;
// Disabling persistent mode when not showing a VR should disable the overall vr mode.
if (!enabled && mCurrentVrModeComponent == null) {
setVrMode(false, null, 0, null);
}
}
}