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 17 package com.android.settingslib.suggestions; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.ServiceConnection; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 import android.service.settings.suggestions.ISuggestionService; 26 import android.service.settings.suggestions.Suggestion; 27 import android.util.Log; 28 29 import androidx.annotation.Nullable; 30 import androidx.annotation.WorkerThread; 31 32 import java.util.List; 33 34 /** 35 * A controller class to access suggestion data. 36 */ 37 public class SuggestionController { 38 39 /** 40 * Callback interface when service is connected/disconnected. 41 */ 42 public interface ServiceConnectionListener { 43 /** 44 * Called when service is connected. 45 */ onServiceConnected()46 void onServiceConnected(); 47 48 /** 49 * Called when service is disconnected. 50 */ onServiceDisconnected()51 void onServiceDisconnected(); 52 } 53 54 private static final String TAG = "SuggestionController"; 55 private static final boolean DEBUG = false; 56 57 private final Context mContext; 58 private final Intent mServiceIntent; 59 60 private ServiceConnection mServiceConnection; 61 private ISuggestionService mRemoteService; 62 private ServiceConnectionListener mConnectionListener; 63 64 /** 65 * Create a new controller instance. 66 * 67 * @param context caller context 68 * @param service The component name for service. 69 * @param listener listener to receive service connected/disconnected event. 70 */ SuggestionController(Context context, ComponentName service, ServiceConnectionListener listener)71 public SuggestionController(Context context, ComponentName service, 72 ServiceConnectionListener listener) { 73 mContext = context.getApplicationContext(); 74 mConnectionListener = listener; 75 mServiceIntent = new Intent().setComponent(service); 76 mServiceConnection = createServiceConnection(); 77 } 78 79 /** 80 * Start the controller. 81 */ start()82 public void start() { 83 mContext.bindServiceAsUser(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE, 84 android.os.Process.myUserHandle()); 85 } 86 87 /** 88 * Stop the controller. 89 */ stop()90 public void stop() { 91 if (mRemoteService != null) { 92 mRemoteService = null; 93 mContext.unbindService(mServiceConnection); 94 } 95 } 96 97 /** 98 * Get setting suggestions. 99 */ 100 @Nullable 101 @WorkerThread getSuggestions()102 public List<Suggestion> getSuggestions() { 103 if (!isReady()) { 104 return null; 105 } 106 try { 107 return mRemoteService.getSuggestions(); 108 } catch (NullPointerException e) { 109 Log.w(TAG, "mRemote service detached before able to query", e); 110 return null; 111 } catch (RemoteException | RuntimeException e) { 112 Log.w(TAG, "Error when calling getSuggestion()", e); 113 return null; 114 } 115 } 116 dismissSuggestions(Suggestion suggestion)117 public void dismissSuggestions(Suggestion suggestion) { 118 if (!isReady()) { 119 Log.w(TAG, "SuggestionController not ready, cannot dismiss " + suggestion.getId()); 120 return; 121 } 122 try { 123 mRemoteService.dismissSuggestion(suggestion); 124 } catch (RemoteException | RuntimeException e) { 125 Log.w(TAG, "Error when calling dismissSuggestion()", e); 126 } 127 } 128 launchSuggestion(Suggestion suggestion)129 public void launchSuggestion(Suggestion suggestion) { 130 if (!isReady()) { 131 Log.w(TAG, "SuggestionController not ready, cannot launch " + suggestion.getId()); 132 return; 133 } 134 135 try { 136 mRemoteService.launchSuggestion(suggestion); 137 } catch (RemoteException | RuntimeException e) { 138 Log.w(TAG, "Error when calling launchSuggestion()", e); 139 } 140 } 141 142 /** 143 * Whether or not the manager is ready 144 */ isReady()145 private boolean isReady() { 146 return mRemoteService != null; 147 } 148 149 /** 150 * Create a new {@link ServiceConnection} object to handle service connect/disconnect event. 151 */ createServiceConnection()152 private ServiceConnection createServiceConnection() { 153 return new ServiceConnection() { 154 155 @Override 156 public void onServiceConnected(ComponentName name, IBinder service) { 157 if (DEBUG) { 158 Log.d(TAG, "Service is connected"); 159 } 160 mRemoteService = ISuggestionService.Stub.asInterface(service); 161 if (mConnectionListener != null) { 162 mConnectionListener.onServiceConnected(); 163 } 164 } 165 166 @Override 167 public void onServiceDisconnected(ComponentName name) { 168 if (mConnectionListener != null) { 169 mRemoteService = null; 170 mConnectionListener.onServiceDisconnected(); 171 } 172 } 173 }; 174 } 175 } 176