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.ambient;
17
18import android.app.Activity;
19import android.os.Bundle;
20
21import androidx.annotation.RestrictTo;
22
23import com.google.android.wearable.compat.WearableActivityController;
24
25import java.lang.reflect.Method;
26
27/**
28 * Provides a {@link WearableActivityController} for ambient mode control.
29 *
30 * @hide
31 */
32@RestrictTo(RestrictTo.Scope.LIBRARY)
33public class WearableControllerProvider {
34
35    private static final String TAG = "WearableControllerProvider";
36
37    private static volatile boolean sAmbientCallbacksVerifiedPresent;
38
39    /**
40     * Retrieves a {@link WearableActivityController} to use for ambient mode.
41     *
42     * @param activity The {@link Activity} to be associated with the Controller.
43     * @param callback The {@link AmbientDelegate.AmbientCallback} for the Controller.
44     * @return the platform-appropriate version of the {@link WearableActivityController}.
45     */
46    public WearableActivityController getWearableController(Activity activity,
47            final AmbientDelegate.AmbientCallback callback) {
48        SharedLibraryVersion.verifySharedLibraryPresent();
49
50        // The AmbientCallback is an abstract class instead of an interface.
51        WearableActivityController.AmbientCallback callbackBridge =
52                new WearableActivityController.AmbientCallback() {
53                    @Override
54                    public void onEnterAmbient(Bundle ambientDetails) {
55                        callback.onEnterAmbient(ambientDetails);
56                    }
57
58                    @Override
59                    public void onUpdateAmbient() {
60                        callback.onUpdateAmbient();
61                    }
62
63                    @Override
64                    public void onExitAmbient() {
65                        callback.onExitAmbient();
66                    }
67                };
68
69        verifyAmbientCallbacksPresent();
70
71        return new WearableActivityController(TAG, activity, callbackBridge);
72    }
73
74    private static void verifyAmbientCallbacksPresent() {
75        if (sAmbientCallbacksVerifiedPresent) {
76            return;
77        }
78        try {
79            Method method =
80                    WearableActivityController.AmbientCallback.class.getDeclaredMethod(
81                            "onEnterAmbient", Bundle.class);
82            // Proguard is sneaky -- it will actually rewrite strings it finds in addition to
83            // function names. Therefore add a "." prefix to the method name check to ensure the
84            // function was not renamed by proguard.
85            if (!(".onEnterAmbient".equals("." + method.getName()))) {
86                throw new NoSuchMethodException();
87            }
88        } catch (NoSuchMethodException e) {
89            throw new IllegalStateException(
90                    "Could not find a required method for "
91                            + "ambient support, likely due to proguard optimization. Please add "
92                            + "com.google.android.wearable:wearable jar to the list of library jars"
93                            + " for your project");
94        }
95        sAmbientCallbacksVerifiedPresent = true;
96    }
97}
98