11a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu/* 21a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Copyright (C) 2017 The Android Open Source Project 31a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * 41a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Licensed under the Apache License, Version 2.0 (the "License"); 51a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * you may not use this file except in compliance with the License. 61a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * You may obtain a copy of the License at 71a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * 81a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * http://www.apache.org/licenses/LICENSE-2.0 91a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * 101a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Unless required by applicable law or agreed to in writing, software 111a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * distributed under the License is distributed on an "AS IS" BASIS, 121a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * See the License for the specific language governing permissions and 141a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * limitations under the License. 151a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 161a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 171a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liupackage com.android.settingslib.suggestions; 181a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 191a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.content.ComponentName; 201a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.content.Context; 211a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.content.Intent; 221a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.content.ServiceConnection; 231a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.os.IBinder; 241a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.os.RemoteException; 251a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.service.settings.suggestions.ISuggestionService; 261a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.service.settings.suggestions.Suggestion; 271a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.support.annotation.Nullable; 281a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.support.annotation.WorkerThread; 291a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport android.util.Log; 301a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 311a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liuimport java.util.List; 321a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 331a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu/** 341a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * A controller class to access suggestion data. 351a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 361a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liupublic class SuggestionController { 371a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 381a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 391a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Callback interface when service is connected/disconnected. 401a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 411a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public interface ServiceConnectionListener { 421a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 431a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Called when service is connected. 441a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 451a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu void onServiceConnected(); 461a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 471a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 481a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Called when service is disconnected. 491a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 501a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu void onServiceDisconnected(); 511a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 521a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 531a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private static final String TAG = "SuggestionController"; 541a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private static final boolean DEBUG = false; 551a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 561a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private final Context mContext; 571a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private final Intent mServiceIntent; 581a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 591a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private ServiceConnection mServiceConnection; 601a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private ISuggestionService mRemoteService; 611a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private ServiceConnectionListener mConnectionListener; 621a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 631a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 641a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Create a new controller instance. 651a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * 661a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * @param context caller context 671a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * @param service The component name for service. 681a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * @param listener listener to receive service connected/disconnected event. 691a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 701a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public SuggestionController(Context context, ComponentName service, 711a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu ServiceConnectionListener listener) { 721a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mContext = context.getApplicationContext(); 731a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mConnectionListener = listener; 741a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mServiceIntent = new Intent().setComponent(service); 751a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mServiceConnection = createServiceConnection(); 761a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 771a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 781a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 791a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Start the controller. 801a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 811a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void start() { 821a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mContext.bindServiceAsUser(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE, 831a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu android.os.Process.myUserHandle()); 841a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 851a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 861a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 871a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Stop the controller. 881a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 891a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void stop() { 901a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (mRemoteService != null) { 911a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mRemoteService = null; 921a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mContext.unbindService(mServiceConnection); 931a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 941a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 951a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 961a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 971a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Get setting suggestions. 981a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 991a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu @Nullable 1001a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu @WorkerThread 1011a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public List<Suggestion> getSuggestions() { 1021a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (!isReady()) { 1031a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return null; 1041a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1051a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu try { 1061a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return mRemoteService.getSuggestions(); 1071a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } catch (NullPointerException e) { 1081a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "mRemote service detached before able to query", e); 1091a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return null; 110df74a5b16fbc7ab7553bc520cc46a9879b65543aZhizhi Liu } catch (RemoteException | RuntimeException e) { 1111a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "Error when calling getSuggestion()", e); 1121a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return null; 1131a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1141a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1151a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1161a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void dismissSuggestions(Suggestion suggestion) { 1171a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (!isReady()) { 1181a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "SuggestionController not ready, cannot dismiss " + suggestion.getId()); 1191a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return; 1201a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1211a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu try { 1221a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mRemoteService.dismissSuggestion(suggestion); 123df74a5b16fbc7ab7553bc520cc46a9879b65543aZhizhi Liu } catch (RemoteException | RuntimeException e) { 1241a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "Error when calling dismissSuggestion()", e); 1251a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1261a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1271a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1281a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void launchSuggestion(Suggestion suggestion) { 1291a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (!isReady()) { 1301a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "SuggestionController not ready, cannot launch " + suggestion.getId()); 1311a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return; 1321a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1331a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1341a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu try { 1351a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mRemoteService.launchSuggestion(suggestion); 136df74a5b16fbc7ab7553bc520cc46a9879b65543aZhizhi Liu } catch (RemoteException | RuntimeException e) { 1371a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.w(TAG, "Error when calling launchSuggestion()", e); 1381a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1391a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1401a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1411a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 1421a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Whether or not the manager is ready 1431a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 1441a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private boolean isReady() { 1451a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return mRemoteService != null; 1461a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1471a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1481a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu /** 1491a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu * Create a new {@link ServiceConnection} object to handle service connect/disconnect event. 1501a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu */ 1511a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu private ServiceConnection createServiceConnection() { 1521a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu return new ServiceConnection() { 1531a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1541a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu @Override 1551a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void onServiceConnected(ComponentName name, IBinder service) { 1561a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (DEBUG) { 1571a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu Log.d(TAG, "Service is connected"); 1581a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1591a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mRemoteService = ISuggestionService.Stub.asInterface(service); 1601a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (mConnectionListener != null) { 1611a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mConnectionListener.onServiceConnected(); 1621a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1631a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1641a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu 1651a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu @Override 1661a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu public void onServiceDisconnected(ComponentName name) { 1671a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu if (mConnectionListener != null) { 1681a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mRemoteService = null; 1691a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu mConnectionListener.onServiceDisconnected(); 1701a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1711a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1721a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu }; 1731a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu } 1741a35c133d23422d09d56f1edcd6b222d83b39170Zhizhi Liu} 175