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