VoiceInteractionSessionConnection.java revision ffeecb1bfb9b71f4b62c9ef1fbf7b58a7a63f655
1/*
2 * Copyright (C) 2015 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
17package com.android.server.voiceinteraction;
18
19import android.app.ActivityManagerNative;
20import android.app.IActivityManager;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.Binder;
26import android.os.Bundle;
27import android.os.IBinder;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.os.UserHandle;
31import android.service.voice.IVoiceInteractionSession;
32import android.service.voice.IVoiceInteractionSessionService;
33import android.service.voice.VoiceInteractionService;
34import android.util.Slog;
35import android.view.IWindowManager;
36import android.view.WindowManager;
37import com.android.internal.app.IVoiceInteractor;
38import com.android.internal.os.IResultReceiver;
39
40import java.io.PrintWriter;
41
42final class VoiceInteractionSessionConnection implements ServiceConnection {
43    final static String TAG = "VoiceInteractionServiceManager";
44
45    final IBinder mToken = new Binder();
46    final Object mLock;
47    final ComponentName mSessionComponentName;
48    final Intent mBindIntent;
49    final int mUser;
50    final Context mContext;
51    final Callback mCallback;
52    final int mCallingPid;
53    final int mCallingUid;
54    final IActivityManager mAm;
55    final IWindowManager mIWindowManager;
56    boolean mShown;
57    Bundle mShowArgs;
58    int mShowFlags;
59    boolean mBound;
60    boolean mFullyBound;
61    boolean mCanceled;
62    IVoiceInteractionSessionService mService;
63    IVoiceInteractionSession mSession;
64    IVoiceInteractor mInteractor;
65    boolean mHaveAssistData;
66    Bundle mAssistData;
67
68    public interface Callback {
69        public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
70    }
71
72    final ServiceConnection mFullConnection = new ServiceConnection() {
73        @Override
74        public void onServiceConnected(ComponentName name, IBinder service) {
75        }
76        @Override
77        public void onServiceDisconnected(ComponentName name) {
78        }
79    };
80
81    final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
82        @Override
83        public void send(int resultCode, Bundle resultData) throws RemoteException {
84            synchronized (mLock) {
85                if (mShown) {
86                    if (mSession != null) {
87                        try {
88                            mSession.handleAssist(resultData);
89                        } catch (RemoteException e) {
90                        }
91                    } else {
92                        mHaveAssistData = true;
93                        mAssistData = resultData;
94                    }
95                }
96            }
97        }
98    };
99
100    public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
101            Context context, Callback callback, int callingPid, int callingUid) {
102        mLock = lock;
103        mSessionComponentName = component;
104        mUser = user;
105        mContext = context;
106        mCallback = callback;
107        mCallingPid = callingPid;
108        mCallingUid = callingUid;
109        mAm = ActivityManagerNative.getDefault();
110        mIWindowManager = IWindowManager.Stub.asInterface(
111                ServiceManager.getService(Context.WINDOW_SERVICE));
112        mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
113        mBindIntent.setComponent(mSessionComponentName);
114        mBound = mContext.bindServiceAsUser(mBindIntent, this,
115                Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
116        if (mBound) {
117            try {
118                mIWindowManager.addWindowToken(mToken,
119                        WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
120            } catch (RemoteException e) {
121                Slog.w(TAG, "Failed adding window token", e);
122            }
123        } else {
124            Slog.w(TAG, "Failed binding to voice interaction session service "
125                    + mSessionComponentName);
126        }
127    }
128
129    public boolean showLocked(Bundle args, int flags) {
130        if (mBound) {
131            if (!mFullyBound) {
132                mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
133                        Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
134                        new UserHandle(mUser));
135            }
136            mShown = true;
137            mShowArgs = args;
138            mShowFlags = flags;
139            if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
140                try {
141                    mAm.requestAssistContextExtras(0, mAssistReceiver);
142                } catch (RemoteException e) {
143                }
144            } else {
145                mHaveAssistData = false;
146                mAssistData = null;
147            }
148            if (mSession != null) {
149                try {
150                    mSession.show(mShowArgs, mShowFlags);
151                    mShowArgs = null;
152                    mShowFlags = 0;
153                } catch (RemoteException e) {
154                }
155                if (mHaveAssistData) {
156                    try {
157                        mSession.handleAssist(mAssistData);
158                        mAssistData = null;
159                        mHaveAssistData = false;
160                    } catch (RemoteException e) {
161                    }
162                }
163            }
164            return true;
165        }
166        return false;
167    }
168
169    public boolean hideLocked() {
170        if (mBound) {
171            if (mShown) {
172                mShown = false;
173                mShowArgs = null;
174                mShowFlags = 0;
175                mHaveAssistData = false;
176                mAssistData = null;
177                if (mSession != null) {
178                    try {
179                        mSession.hide();
180                    } catch (RemoteException e) {
181                    }
182                }
183            }
184            if (mFullyBound) {
185                mContext.unbindService(mFullConnection);
186                mFullyBound = false;
187            }
188            return true;
189        }
190        return false;
191    }
192
193    public boolean deliverNewSessionLocked(IVoiceInteractionSession session,
194            IVoiceInteractor interactor) {
195        mSession = session;
196        mInteractor = interactor;
197        if (mShown) {
198            try {
199                session.show(mShowArgs, mShowFlags);
200                mShowArgs = null;
201                mShowFlags = 0;
202            } catch (RemoteException e) {
203            }
204            if (mHaveAssistData) {
205                try {
206                    session.handleAssist(mAssistData);
207                    mAssistData = null;
208                    mHaveAssistData = false;
209                } catch (RemoteException e) {
210                }
211            }
212        }
213        return true;
214    }
215
216    @Override
217    public void onServiceConnected(ComponentName name, IBinder service) {
218        synchronized (mLock) {
219            mService = IVoiceInteractionSessionService.Stub.asInterface(service);
220            if (!mCanceled) {
221                try {
222                    mService.newSession(mToken, mShowArgs, mShowFlags);
223                } catch (RemoteException e) {
224                    Slog.w(TAG, "Failed adding window token", e);
225                }
226            }
227        }
228    }
229
230    @Override
231    public void onServiceDisconnected(ComponentName name) {
232        mCallback.sessionConnectionGone(this);
233        mService = null;
234    }
235
236    public void cancel() {
237        mCanceled = true;
238        if (mBound) {
239            if (mSession != null) {
240                try {
241                    mSession.destroy();
242                } catch (RemoteException e) {
243                    Slog.w(TAG, "Voice interation session already dead");
244                }
245            }
246            if (mSession != null) {
247                try {
248                    mAm.finishVoiceTask(mSession);
249                } catch (RemoteException e) {
250                }
251            }
252            mContext.unbindService(this);
253            try {
254                mIWindowManager.removeWindowToken(mToken);
255            } catch (RemoteException e) {
256                Slog.w(TAG, "Failed removing window token", e);
257            }
258            mBound = false;
259            mService = null;
260            mSession = null;
261            mInteractor = null;
262        }
263        if (mFullyBound) {
264            mContext.unbindService(mFullConnection);
265            mFullyBound = false;
266        }
267    }
268
269    public void dump(String prefix, PrintWriter pw) {
270        pw.print(prefix); pw.print("mToken="); pw.println(mToken);
271        pw.print(prefix); pw.print("mShown="); pw.println(mShown);
272        pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs);
273        pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags));
274        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
275        if (mBound) {
276            pw.print(prefix); pw.print("mService="); pw.println(mService);
277            pw.print(prefix); pw.print("mSession="); pw.println(mSession);
278            pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
279        }
280        pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
281        if (mHaveAssistData) {
282            pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
283        }
284    }
285};
286