1/*
2 * Copyright (C) 2017 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 androidx.wear.utils;
17
18import android.content.Context;
19import android.content.pm.ApplicationInfo;
20import android.content.pm.PackageManager;
21
22/**
23 * Constants for android wear apps which are related to manifest meta-data.
24 */
25public class MetadataConstants {
26
27    //  Constants for standalone apps. //
28
29    /**
30     * The name of the meta-data element in the Wear app manifest for specifying whether this app
31     * does not require a companion phone app. The value should be set to "true" or "false".
32     * <p>
33     * <p>Wear apps that do not require a phone side companion app to function can declare this in
34     * their AndroidManifest.xml file by setting the standalone meta-data element to true as shown
35     * in the following example. If this value is true, all users can discover this app regardless
36     * of what phone they have. If this value is false (or not set), only users with compatible
37     * Android phones can discover this app.
38     * <p>
39     * <pre class="prettyprint">{@code
40     * <meta-data
41     * android:name="com.google.android.wearable.standalone"
42     * android:value="true" />
43     * }</pre>
44     */
45    public static final String STANDALONE_METADATA_NAME = "com.google.android.wearable.standalone";
46
47    //  Constants for customizing bridging of notifications from the phone to the wearable. //
48
49    /**
50     * We support specifying whether notifications should be bridged from the phone to the wearable
51     * in the Wear app manifest file. Simply add a meta-data element to the Wear app manifest with
52     * the name "com.google.android.wearable.notificationBridgeMode" and either the value
53     * NO_BRIDGING or the value BRIDGING. If you choose not to update your Wear app manifest, then
54     * notifications will be bridged by default from the phone to the wearable.
55     *
56     * <p>NO_BRIDGING means that phone notifications will not be bridged to the wearable if the
57     * wearable app is installed.
58     *
59     * <p>BRIDGING means that phone notifications will be bridged to the wearable, unless they are
60     * posted with
61     * {@link android.app.Notification.Builder#setLocalOnly(boolean) setLocalOnly(true)}.
62     *
63     * <p>Example AndroidManifest.xml meta-data element for NO_BRIDGING:
64     *
65     * <pre class="prettyprint">{@code
66     * <meta-data
67     *     android:name="com.google.android.wearable.notificationBridgeMode"
68     *     android:value="NO_BRIDGING" />
69     * }</pre>
70     *
71     * <p>Example AndroidManifest.xml meta-data element for BRIDGING:
72     *
73     * <pre class="prettyprint">{@code
74     * <meta-data
75     *     android:name="com.google.android.wearable.notificationBridgeMode"
76     *     android:value="BRIDGING" />
77     * }</pre>
78     */
79    public static final String NOTIFICATION_BRIDGE_MODE_METADATA_NAME =
80            "com.google.android.wearable.notificationBridgeMode";
81
82    /**
83     * The value of the notification bridge mode meta-data element in the case where the Wear app
84     * wants notifications to be bridged from the phone to the wearable.
85     */
86    public static final String NOTIFICATION_BRIDGE_MODE_BRIDGING = "BRIDGING";
87
88    /**
89     * The value of the notification bridge mode meta-data element in the case where the Wear app
90     * does not want notifications to be bridged from the phone to the wearable.
91     */
92    public static final String NOTIFICATION_BRIDGE_MODE_NO_BRIDGING = "NO_BRIDGING";
93
94    //  Constants for watch face preview. //
95
96    /**
97     * The name of the meta-data element in the watch face service manifest declaration used
98     * to assign a non-circular preview image to the watch face. The value should be set to
99     * a drawable reference.
100     *
101     * <pre class="prettyprint">
102     * &lt;meta-data
103     *     android:name="com.google.android.wearable.watchface.preview"
104     *     android:resource="@drawable/preview_face" /&gt;
105     * </pre>
106     */
107    public static final String WATCH_FACE_PREVIEW_METADATA_NAME =
108            "com.google.android.wearable.watchface.preview";
109
110    /**
111     * The name of the meta-data element in the watch face service manifest declaration used
112     * to assign a circular preview image to the watch face. The value should be set to
113     * a drawable reference.
114     *
115     * <pre class="prettyprint">
116     * &lt;meta-data
117     *     android:name="com.google.android.wearable.watchface.preview_circular"
118     *     android:resource="@drawable/preview_face_circular" /&gt;
119     * </pre>
120     */
121    public static final String WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME =
122            "com.google.android.wearable.watchface.preview_circular";
123
124    // HELPER METHODS //
125
126    /**
127     * Determines whether a given context comes from a standalone app. This can be used as a proxy
128     * to check if any given app is compatible with iOS Companion devices.
129     *
130     * @param context to be evaluated.
131     * @return Whether a given context comes from a standalone app.
132     */
133    public static boolean isStandalone(Context context) {
134        try {
135            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
136                    context.getPackageName(), PackageManager.GET_META_DATA);
137            if (appInfo.metaData != null) {
138                return appInfo.metaData.getBoolean(STANDALONE_METADATA_NAME);
139            }
140        } catch (PackageManager.NameNotFoundException e) {
141            // Do nothing
142        }
143
144        return false;
145    }
146
147    /**
148     * Determines whether a given context has notification bridging enabled.
149     *
150     * @param context to be evaluated.
151     * @return Whether a given context has notification bridging enabled.
152     */
153    public static boolean isNotificationBridgingEnabled(Context context) {
154        try {
155            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
156                    context.getPackageName(), PackageManager.GET_META_DATA);
157            if (appInfo.metaData != null) {
158                return NOTIFICATION_BRIDGE_MODE_BRIDGING.equals(
159                        appInfo.metaData.getString(NOTIFICATION_BRIDGE_MODE_METADATA_NAME));
160            }
161        } catch (PackageManager.NameNotFoundException e) {
162            // Do nothing
163        }
164
165        return true;
166    }
167
168    /**
169     *
170     * @param context to be evaluated.
171     * @param circular Whether to return the circular or regular preview.
172     *
173     * @return an integer id representing the resource id of the requested drawable, or 0 if
174     * no drawable was found.
175     */
176    public static int getPreviewDrawableResourceId(Context context, boolean circular) {
177        try {
178            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
179                    context.getPackageName(), PackageManager.GET_META_DATA);
180            if (appInfo.metaData != null) {
181                return circular
182                        ?  appInfo.metaData.getInt(WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME, 0)
183                        :  appInfo.metaData.getInt(WATCH_FACE_PREVIEW_METADATA_NAME, 0);
184            }
185        } catch (PackageManager.NameNotFoundException e) {
186            // Do nothing
187        }
188
189        return 0;
190    }
191
192    private MetadataConstants() {}
193}
194