1/**
2 * Copyright (C) 2016 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 */
16
17package android.service.vr;
18
19import android.annotation.NonNull;
20import android.annotation.SdkConstant;
21import android.app.ActivityManager;
22import android.app.Service;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.Looper;
29import android.os.Message;
30
31/**
32 * A service that is bound from the system while running in virtual reality (VR) mode.
33 *
34 * <p>To extend this class, you must declare the service in your manifest file with
35 * the {@link android.Manifest.permission#BIND_VR_LISTENER_SERVICE} permission
36 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
37 * <pre>
38 * &lt;service android:name=".VrListener"
39 *          android:label="&#64;string/service_name"
40 *          android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
41 *     &lt;intent-filter>
42 *         &lt;action android:name="android.service.vr.VrListenerService" />
43 *     &lt;/intent-filter>
44 * &lt;/service>
45 * </pre>
46 *
47 * <p>This service is bound when the system enters VR mode and is unbound when the system leaves VR
48 * mode.</p>
49 * <p>The system will enter VR mode when an application that has previously called
50 * {@link android.app.Activity#setVrModeEnabled} gains user focus.  The system will only start this
51 * service if the VR application has specifically targeted this service by specifying
52 * its {@link ComponentName} in the call to {@link android.app.Activity#setVrModeEnabled} and if
53 * this service is installed and enabled in the current user's settings.</p>
54 *
55 * @see android.provider.Settings#ACTION_VR_LISTENER_SETTINGS
56 * @see android.app.Activity#setVrModeEnabled
57 * @see android.R.attr#enableVrMode
58 */
59public abstract class VrListenerService extends Service {
60
61    /**
62     * The {@link Intent} that must be declared as handled by the service.
63     */
64    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
65    public static final String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
66
67    private final Handler mHandler;
68
69    private static final int MSG_ON_CURRENT_VR_ACTIVITY_CHANGED = 1;
70
71    private final IVrListener.Stub mBinder = new IVrListener.Stub() {
72        @Override
73        public void focusedActivityChanged(ComponentName component) {
74            mHandler.obtainMessage(MSG_ON_CURRENT_VR_ACTIVITY_CHANGED, component).sendToTarget();
75        }
76    };
77
78    private final class VrListenerHandler extends Handler {
79        public VrListenerHandler(Looper looper) {
80            super(looper);
81        }
82
83        @Override
84        public void handleMessage(Message msg) {
85            switch (msg.what) {
86                case MSG_ON_CURRENT_VR_ACTIVITY_CHANGED: {
87                    VrListenerService.this.onCurrentVrActivityChanged((ComponentName) msg.obj);
88                } break;
89            }
90        }
91    }
92
93    @Override
94    public IBinder onBind(Intent intent) {
95        return mBinder;
96    }
97
98    public VrListenerService() {
99        mHandler = new VrListenerHandler(Looper.getMainLooper());
100    }
101
102    /**
103     * Called when the current activity using VR mode has changed.
104     *
105     * <p>This will be called when this service is initially bound, but is not
106     * guaranteed to be called before onUnbind.  In general, this is intended to be used to
107     * determine when user focus has transitioned between two VR activities.  If both activities
108     * have declared {@link android.R.attr#enableVrMode} with this service (and this
109     * service is present and enabled), this service will not be unbound during the activity
110     * transition.</p>
111     *
112     * @param component the {@link ComponentName} of the VR activity that the system has
113     *    switched to, or null if the system is displaying a 2D activity in VR compatibility mode.
114     *
115     * @see android.app.Activity#setVrModeEnabled
116     * @see android.R.attr#enableVrMode
117     */
118    public void onCurrentVrActivityChanged(ComponentName component) {
119        // Override to implement
120    }
121
122    /**
123     * Checks if the given component is enabled in user settings.
124     *
125     * <p>If this component is not enabled in the user's settings, it will not be started when
126     * the system enters VR mode.  The user interface for enabling VrListenerService components
127     * can be started by sending the {@link android.provider.Settings#ACTION_VR_LISTENER_SETTINGS}
128     * intent.</p>
129     *
130     * @param context the {@link Context} to use for looking up the requested component.
131     * @param requestedComponent the name of the component that implements
132     * {@link android.service.vr.VrListenerService} to check.
133     *
134     * @return {@code true} if this component is enabled in settings.
135     *
136     * @see android.provider.Settings#ACTION_VR_LISTENER_SETTINGS
137     */
138    public static final boolean isVrModePackageEnabled(@NonNull Context context,
139            @NonNull ComponentName requestedComponent) {
140        ActivityManager am = context.getSystemService(ActivityManager.class);
141        if (am == null) {
142            return false;
143        }
144        return am.isVrModePackageEnabled(requestedComponent);
145    }
146}
147