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