blob: c572e766f1ec17995de3f599856782af7cd1ea61 [file] [log] [blame]
Ruben Brunke24b9a62016-02-16 21:38:24 -08001/**
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08002 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.vr;
17
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080018import android.app.AppOpsManager;
Ruben Brunk98576cf2016-03-07 18:54:28 -080019import android.app.NotificationManager;
Ruben Brunke24b9a62016-02-16 21:38:24 -080020import android.annotation.NonNull;
Ruben Brunke24b9a62016-02-16 21:38:24 -080021import android.content.ComponentName;
Ruben Brunk98576cf2016-03-07 18:54:28 -080022import android.content.ContentResolver;
23import android.content.Context;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.PackageManager.NameNotFoundException;
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080027import android.os.Binder;
Ruben Brunke24b9a62016-02-16 21:38:24 -080028import android.os.Handler;
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080029import android.os.IBinder;
Ruben Brunke24b9a62016-02-16 21:38:24 -080030import android.os.IInterface;
31import android.os.Looper;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080032import android.os.RemoteException;
Ruben Brunk98576cf2016-03-07 18:54:28 -080033import android.os.UserHandle;
Ruben Brunke24b9a62016-02-16 21:38:24 -080034import android.provider.Settings;
Ruben Brunk98576cf2016-03-07 18:54:28 -080035import android.service.notification.NotificationListenerService;
Ruben Brunke24b9a62016-02-16 21:38:24 -080036import android.service.vr.IVrListener;
37import android.service.vr.VrListenerService;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080038import android.util.ArraySet;
39import android.util.Slog;
40
Ruben Brunke24b9a62016-02-16 21:38:24 -080041import com.android.internal.R;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080042import com.android.server.SystemService;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080043import com.android.server.utils.ManagedApplicationService.PendingEvent;
Ruben Brunke24b9a62016-02-16 21:38:24 -080044import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
45import com.android.server.utils.ManagedApplicationService;
46import com.android.server.utils.ManagedApplicationService.BinderChecker;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080047
Ruben Brunk98576cf2016-03-07 18:54:28 -080048import java.lang.StringBuilder;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080049import java.util.ArrayList;
Ruben Brunk98576cf2016-03-07 18:54:28 -080050import java.util.Collection;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080051import java.util.Objects;
Ruben Brunke24b9a62016-02-16 21:38:24 -080052import java.util.Set;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080053
54/**
Ruben Brunke24b9a62016-02-16 21:38:24 -080055 * Service tracking whether VR mode is active, and notifying listening services of state changes.
56 * <p/>
57 * Services running in system server may modify the state of VrManagerService via the interface in
58 * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the
59 * interface given in VrStateListener.
60 * <p/>
61 * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.:
62 * hardware/libhardware/modules/vr
63 * <p/>
64 * In general applications may enable or disable VR mode by calling
Ruben Brunk98576cf2016-03-07 18:54:28 -080065 * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to
66 * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080067 *
Ruben Brunke24b9a62016-02-16 21:38:24 -080068 * @see {@link android.service.vr.VrListenerService}
69 * @see {@link com.android.server.vr.VrManagerInternal}
70 * @see {@link com.android.server.vr.VrStateListener}
71 *
72 * @hide
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080073 */
Ruben Brunke24b9a62016-02-16 21:38:24 -080074public class VrManagerService extends SystemService implements EnabledComponentChangeListener{
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080075
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080076 public static final String TAG = "VrManagerService";
77
Ruben Brunkbaa4b552016-02-02 16:27:37 -080078 private static native void initializeNative();
79 private static native void setVrModeNative(boolean enabled);
80
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080081 private final Object mLock = new Object();
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080082
83 private final IBinder mOverlayToken = new Binder();
84
Ruben Brunke24b9a62016-02-16 21:38:24 -080085 // State protected by mLock
Ruben Brunk98576cf2016-03-07 18:54:28 -080086 private boolean mVrModeEnabled;
Ruben Brunke24b9a62016-02-16 21:38:24 -080087 private final Set<VrStateListener> mListeners = new ArraySet<>();
88 private EnabledComponentsObserver mComponentObserver;
89 private ManagedApplicationService mCurrentVrService;
90 private Context mContext;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080091 private ComponentName mCurrentVrModeComponent;
92 private int mCurrentVrModeUser;
Ruben Brunk98576cf2016-03-07 18:54:28 -080093 private boolean mWasDefaultGranted;
94 private boolean mGuard;
95 private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
96 private String mPreviousNotificationPolicyAccessPackage;
97 private String mPreviousManageOverlayPackage;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080098
Ruben Brunke24b9a62016-02-16 21:38:24 -080099 private static final BinderChecker sBinderChecker = new BinderChecker() {
100 @Override
101 public IInterface asInterface(IBinder binder) {
102 return IVrListener.Stub.asInterface(binder);
103 }
104
105 @Override
106 public boolean checkType(IInterface service) {
107 return service instanceof IVrListener;
108 }
109 };
110
111 /**
112 * Called when a user, package, or setting changes that could affect whether or not the
113 * currently bound VrListenerService is changed.
114 */
115 @Override
116 public void onEnabledComponentChanged() {
117 synchronized (mLock) {
118 if (mCurrentVrService == null) {
119 return; // No active services
120 }
121
122 // There is an active service, update it if needed
123 updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800124 mCurrentVrService.getUserId(), null);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800125 }
126 }
127
128 /**
129 * Implementation of VrManagerInternal. Callable only from system services.
130 */
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800131 private final class LocalService extends VrManagerInternal {
132 @Override
133 public boolean isInVrMode() {
134 return VrManagerService.this.getVrMode();
135 }
136
137 @Override
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800138 public void setVrMode(boolean enabled, ComponentName packageName, int userId,
139 ComponentName callingPackage) {
140 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800141 }
142
143 @Override
Ruben Brunk8f1d5cb2016-03-22 18:08:41 -0700144 public boolean isCurrentVrListener(String packageName, int userId) {
145 return VrManagerService.this.isCurrentVrListener(packageName, userId);
146 }
147
148 @Override
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800149 public void registerListener(VrStateListener listener) {
150 VrManagerService.this.addListener(listener);
151 }
152
153 @Override
154 public void unregisterListener(VrStateListener listener) {
155 VrManagerService.this.removeListener(listener);
156 }
Ruben Brunke24b9a62016-02-16 21:38:24 -0800157
158 @Override
159 public int hasVrPackage(ComponentName packageName, int userId) {
160 return VrManagerService.this.hasVrPackage(packageName, userId);
161 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800162 }
163
164 public VrManagerService(Context context) {
165 super(context);
166 }
167
168 @Override
169 public void onStart() {
Ruben Brunkbaa4b552016-02-02 16:27:37 -0800170 synchronized(mLock) {
171 initializeNative();
Ruben Brunke24b9a62016-02-16 21:38:24 -0800172 mContext = getContext();
Ruben Brunkbaa4b552016-02-02 16:27:37 -0800173 }
174
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800175 publishLocalService(VrManagerInternal.class, new LocalService());
176 }
177
Ruben Brunke24b9a62016-02-16 21:38:24 -0800178 @Override
179 public void onBootPhase(int phase) {
Ruben Brunk85070042016-03-21 12:10:38 -0700180 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800181 synchronized (mLock) {
182 Looper looper = Looper.getMainLooper();
183 Handler handler = new Handler(looper);
184 ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>();
185 listeners.add(this);
186 mComponentObserver = EnabledComponentsObserver.build(mContext, handler,
187 Settings.Secure.ENABLED_VR_LISTENERS, looper,
188 android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
189 VrListenerService.SERVICE_INTERFACE, mLock, listeners);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800190
Ruben Brunke24b9a62016-02-16 21:38:24 -0800191 mComponentObserver.rebuildAll();
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800192 }
193 }
194 }
195
Ruben Brunke24b9a62016-02-16 21:38:24 -0800196 @Override
197 public void onStartUser(int userHandle) {
198 synchronized (mLock) {
199 mComponentObserver.onUsersChanged();
200 }
201 }
202
203 @Override
204 public void onSwitchUser(int userHandle) {
205 synchronized (mLock) {
206 mComponentObserver.onUsersChanged();
207 }
208
209 }
210
211 @Override
212 public void onStopUser(int userHandle) {
213 synchronized (mLock) {
214 mComponentObserver.onUsersChanged();
215 }
216
217 }
218
219 @Override
220 public void onCleanupUser(int userHandle) {
221 synchronized (mLock) {
222 mComponentObserver.onUsersChanged();
223 }
224 }
225
Ruben Brunk29931bc2016-03-11 00:24:26 -0800226 private void updateOverlayStateLocked(ComponentName exemptedComponent) {
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800227 final long identity = Binder.clearCallingIdentity();
228 try {
229 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
230 if (appOpsManager != null) {
Ruben Brunk29931bc2016-03-11 00:24:26 -0800231 String[] exemptions = (exemptedComponent == null) ? new String[0] :
232 new String[] { exemptedComponent.getPackageName() };
233
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800234 appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
Ruben Brunk29931bc2016-03-11 00:24:26 -0800235 mVrModeEnabled, mOverlayToken, exemptions);
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800236 }
237 } finally {
238 Binder.restoreCallingIdentity(identity);
239 }
240 }
241
Ruben Brunke24b9a62016-02-16 21:38:24 -0800242 /**
243 * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of
244 * the currently selected VR listener service. If the component selected for the VR listener
245 * service has changed, unbind the previous listener and bind the new listener (if enabled).
246 * <p/>
247 * Note: Must be called while holding {@code mLock}.
248 *
249 * @param enabled new state for VR mode.
250 * @param component new component to be bound as a VR listener.
251 * @param userId user owning the component to be bound.
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800252 * @param calling the component currently using VR mode, or null to leave unchanged.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800253 *
254 * @return {@code true} if the component/user combination specified is valid.
255 */
Ruben Brunk98576cf2016-03-07 18:54:28 -0800256 private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
257 int userId, ComponentName calling) {
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800258
259 boolean sendUpdatedCaller = false;
Ruben Brunk98576cf2016-03-07 18:54:28 -0800260 final long identity = Binder.clearCallingIdentity();
261 try {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800262
Ruben Brunk98576cf2016-03-07 18:54:28 -0800263 boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
264 EnabledComponentsObserver.NO_ERROR);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800265
Ruben Brunk98576cf2016-03-07 18:54:28 -0800266 // Always send mode change events.
267 changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
Ruben Brunk29931bc2016-03-11 00:24:26 -0800268
Ruben Brunk98576cf2016-03-07 18:54:28 -0800269 if (!enabled || !validUserComponent) {
270 // Unbind whatever is running
271 if (mCurrentVrService != null) {
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800272 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
Ruben Brunk98576cf2016-03-07 18:54:28 -0800273 mCurrentVrService.getUserId());
274 mCurrentVrService.disconnect();
275 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
276 new UserHandle(mCurrentVrService.getUserId()));
277 mCurrentVrService = null;
278 }
279 } else {
280 if (mCurrentVrService != null) {
281 // Unbind any running service that doesn't match the component/user selection
282 if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
283 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
284 " for user " + mCurrentVrService.getUserId());
285 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
286 new UserHandle(mCurrentVrService.getUserId()));
287 createAndConnectService(component, userId);
288 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
289 new UserHandle(mCurrentVrService.getUserId()));
290 sendUpdatedCaller = true;
291 }
292 // The service with the correct component/user is bound
293 } else {
294 // Nothing was previously running, bind a new service
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800295 createAndConnectService(component, userId);
Ruben Brunk98576cf2016-03-07 18:54:28 -0800296 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
297 new UserHandle(mCurrentVrService.getUserId()));
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800298 sendUpdatedCaller = true;
299 }
Ruben Brunk98576cf2016-03-07 18:54:28 -0800300 }
301
302 if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
303 mCurrentVrModeComponent = calling;
304 mCurrentVrModeUser = userId;
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800305 sendUpdatedCaller = true;
306 }
Ruben Brunk98576cf2016-03-07 18:54:28 -0800307
308 if (mCurrentVrService != null && sendUpdatedCaller) {
309 final ComponentName c = mCurrentVrModeComponent;
310 mCurrentVrService.sendEvent(new PendingEvent() {
311 @Override
312 public void runEvent(IInterface service) throws RemoteException {
313 IVrListener l = (IVrListener) service;
314 l.focusedActivityChanged(c);
315 }
316 });
317 }
318
319 return validUserComponent;
320 } finally {
321 Binder.restoreCallingIdentity(identity);
322 }
323 }
324
325 /**
326 * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
327 * component package and user.
328 *
329 * @param component the component whose package should be enabled.
330 * @param userId the user that owns the given component.
331 */
332 private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
333 if (mGuard) {
334 // Impossible
335 throw new IllegalStateException("Enabling permissions without disabling.");
336 }
337 mGuard = true;
338
339 PackageManager pm = mContext.getPackageManager();
340
341 String pName = component.getPackageName();
342 if (pm == null) {
343 Slog.e(TAG, "Couldn't set implied permissions for " + pName +
344 ", PackageManager isn't running");
345 return;
346 }
347
348 ApplicationInfo info = null;
349 try {
350 info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
351 } catch (NameNotFoundException e) {
352 }
353
354 if (info == null) {
355 Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
356 return;
357 }
358
359 if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
360 return; // Application is not pre-installed, avoid setting implied permissions
361 }
362
363 mWasDefaultGranted = true;
364
365 grantOverlayAccess(pName, userId);
366 grantNotificationPolicyAccess(pName);
367 grantNotificationListenerAccess(pName, userId);
368 }
369
370 /**
371 * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
372 * component package and user.
373 *
374 * @param component the component whose package should be disabled.
375 * @param userId the user that owns the given component.
376 */
377 private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
378 if (!mGuard) {
379 // Impossible
380 throw new IllegalStateException("Disabling permissions without enabling.");
381 }
382 mGuard = false;
383
384 PackageManager pm = mContext.getPackageManager();
385
386 if (pm == null) {
387 Slog.e(TAG, "Couldn't remove implied permissions for " + component +
388 ", PackageManager isn't running");
389 return;
390 }
391
392 String pName = component.getPackageName();
393 if (mWasDefaultGranted) {
394 revokeOverlayAccess(userId);
395 revokeNotificationPolicyAccess(pName);
396 revokeNotificiationListenerAccess();
397 mWasDefaultGranted = false;
398 }
399
400 }
401
402 private void grantOverlayAccess(String pkg, UserHandle userId) {
403 PackageManager pm = mContext.getPackageManager();
404 boolean prev = (PackageManager.PERMISSION_GRANTED ==
405 pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
406 mPreviousManageOverlayPackage = null;
407 if (!prev) {
408 pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
409 userId);
410 mPreviousManageOverlayPackage = pkg;
411 }
412 }
413
414 private void revokeOverlayAccess(UserHandle userId) {
415 PackageManager pm = mContext.getPackageManager();
416 if (mPreviousManageOverlayPackage != null) {
417 pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
418 android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
419 mPreviousManageOverlayPackage = null;
420 }
421 }
422
423
424 private void grantNotificationPolicyAccess(String pkg) {
425 NotificationManager nm = mContext.getSystemService(NotificationManager.class);
426 boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
427 mPreviousNotificationPolicyAccessPackage = null;
428 if (!prev) {
429 mPreviousNotificationPolicyAccessPackage = pkg;
430 nm.setNotificationPolicyAccessGranted(pkg, true);
431 }
432 }
433
434 private void revokeNotificationPolicyAccess(String pkg) {
435 NotificationManager nm = mContext.getSystemService(NotificationManager.class);
436 if (mPreviousNotificationPolicyAccessPackage != null) {
437 nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
438 mPreviousNotificationPolicyAccessPackage = null;
439 }
440 }
441
442 private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
443 PackageManager pm = mContext.getPackageManager();
444 ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
445 userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
446 android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
447 ContentResolver resolver = mContext.getContentResolver();
448
449 ArraySet<String> current = getCurrentNotifListeners(resolver);
450
451 mPreviousToggledListenerSettings.clear();
452
453 for (ComponentName c : possibleServices) {
454 String flatName = c.flattenToString();
455 if (Objects.equals(c.getPackageName(), pkg)
456 && !current.contains(flatName)) {
457 mPreviousToggledListenerSettings.add(flatName);
458 current.add(flatName);
459 }
Ruben Brunke24b9a62016-02-16 21:38:24 -0800460 }
461
Ruben Brunk98576cf2016-03-07 18:54:28 -0800462 if (current.size() > 0) {
463 String flatSettings = formatSettings(current);
464 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
465 flatSettings);
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800466 }
Ruben Brunke24b9a62016-02-16 21:38:24 -0800467 }
468
Ruben Brunk98576cf2016-03-07 18:54:28 -0800469 private void revokeNotificiationListenerAccess() {
470 if (mPreviousToggledListenerSettings.isEmpty()) {
471 return;
472 }
473
474 ContentResolver resolver = mContext.getContentResolver();
475 ArraySet<String> current = getCurrentNotifListeners(resolver);
476
477 current.removeAll(mPreviousToggledListenerSettings);
478 mPreviousToggledListenerSettings.clear();
479
480 String flatSettings = formatSettings(current);
481 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
482 flatSettings);
483 }
484
485 private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
486 String flat = Settings.Secure.getString(resolver,
487 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
488
489 ArraySet<String> current = new ArraySet<>();
490 if (flat != null) {
491 String[] allowed = flat.split(":");
492 for (String s : allowed) {
493 current.add(s);
494 }
495 }
496 return current;
497 }
498
499 private static String formatSettings(Collection<String> c) {
500 if (c == null || c.isEmpty()) {
501 return "";
502 }
503
504 StringBuilder b = new StringBuilder();
505 boolean start = true;
506 for (String s : c) {
507 if ("".equals(s)) {
508 continue;
509 }
510 if (!start) {
511 b.append(':');
512 }
513 b.append(s);
514 start = false;
515 }
516 return b.toString();
517 }
518
519
520
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800521 private void createAndConnectService(@NonNull ComponentName component, int userId) {
522 mCurrentVrService = VrManagerService.create(mContext, component, userId);
523 mCurrentVrService.connect();
524 Slog.i(TAG, "Connecting " + component + " for user " + userId);
525 }
526
Ruben Brunke24b9a62016-02-16 21:38:24 -0800527 /**
528 * Send VR mode change callbacks to HAL and system services if mode has actually changed.
529 * <p/>
530 * Note: Must be called while holding {@code mLock}.
531 *
532 * @param enabled new state of the VR mode.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800533 * @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800534 */
Ruben Brunk29931bc2016-03-11 00:24:26 -0800535 private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800536 if (mVrModeEnabled != enabled) {
537 mVrModeEnabled = enabled;
538
539 // Log mode change event.
540 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
541 setVrModeNative(mVrModeEnabled);
542
Ruben Brunk29931bc2016-03-11 00:24:26 -0800543 updateOverlayStateLocked(exemptedComponent);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800544 onVrModeChangedLocked();
545 }
546 }
547
548 /**
549 * Notify system services of VR mode change.
550 * <p/>
551 * Note: Must be called while holding {@code mLock}.
552 */
553 private void onVrModeChangedLocked() {
554 for (VrStateListener l : mListeners) {
555 l.onVrStateChanged(mVrModeEnabled);
556 }
557 }
558
559 /**
560 * Helper function for making ManagedApplicationService instances.
561 */
562 private static ManagedApplicationService create(@NonNull Context context,
563 @NonNull ComponentName component, int userId) {
564 return ManagedApplicationService.build(context, component, userId,
565 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
566 sBinderChecker);
567 }
568
569 /*
570 * Implementation of VrManagerInternal calls. These are callable from system services.
571 */
572
573 private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800574 int userId, @NonNull ComponentName callingPackage) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800575 synchronized (mLock) {
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800576 return updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800577 }
578 }
579
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800580 private boolean getVrMode() {
581 synchronized (mLock) {
582 return mVrModeEnabled;
583 }
584 }
585
Ruben Brunk8f1d5cb2016-03-22 18:08:41 -0700586 private boolean isCurrentVrListener(String packageName, int userId) {
587 synchronized (mLock) {
588 if (mCurrentVrService == null) {
589 return false;
590 }
591 return mCurrentVrService.getComponent().getPackageName().equals(packageName) &&
592 userId == mCurrentVrService.getUserId();
593 }
594 }
595
Ruben Brunke24b9a62016-02-16 21:38:24 -0800596 private void addListener(VrStateListener listener) {
597 synchronized (mLock) {
598 mListeners.add(listener);
599 }
600 }
601
602 private void removeListener(VrStateListener listener) {
603 synchronized (mLock) {
604 mListeners.remove(listener);
605 }
606 }
607
608 private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
609 synchronized (mLock) {
610 return mComponentObserver.isValid(targetPackageName, userId);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800611 }
612 }
613}