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