am c89704a7: merge from open-source master
Merge commit 'c89704a77f9c51ebd8c1cc6863e15ff402a56c86' into kraken * commit 'c89704a77f9c51ebd8c1cc6863e15ff402a56c86': Fix Memory Leak When Switching Input Methods
This commit is contained in:
committed by
Android Git Automerger
commit
f29c7d4d27
@@ -47,9 +47,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
|
|||||||
private static final int DO_UPDATE_CURSOR = 95;
|
private static final int DO_UPDATE_CURSOR = 95;
|
||||||
private static final int DO_APP_PRIVATE_COMMAND = 100;
|
private static final int DO_APP_PRIVATE_COMMAND = 100;
|
||||||
private static final int DO_TOGGLE_SOFT_INPUT = 105;
|
private static final int DO_TOGGLE_SOFT_INPUT = 105;
|
||||||
|
private static final int DO_FINISH_SESSION = 110;
|
||||||
|
|
||||||
final HandlerCaller mCaller;
|
HandlerCaller mCaller;
|
||||||
final InputMethodSession mInputMethodSession;
|
InputMethodSession mInputMethodSession;
|
||||||
|
|
||||||
// NOTE: we should have a cache of these.
|
// NOTE: we should have a cache of these.
|
||||||
static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
|
static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
|
||||||
@@ -127,6 +128,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
|
|||||||
mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
|
mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case DO_FINISH_SESSION: {
|
||||||
|
mInputMethodSession = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Log.w(TAG, "Unhandled message code: " + msg.what);
|
Log.w(TAG, "Unhandled message code: " + msg.what);
|
||||||
}
|
}
|
||||||
@@ -174,4 +179,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
|
|||||||
public void toggleSoftInput(int showFlags, int hideFlags) {
|
public void toggleSoftInput(int showFlags, int hideFlags) {
|
||||||
mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
|
mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void finishSession() {
|
||||||
|
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import android.view.inputmethod.InputMethodSession;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -64,9 +65,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
private static final int DO_SHOW_SOFT_INPUT = 60;
|
private static final int DO_SHOW_SOFT_INPUT = 60;
|
||||||
private static final int DO_HIDE_SOFT_INPUT = 70;
|
private static final int DO_HIDE_SOFT_INPUT = 70;
|
||||||
|
|
||||||
final AbstractInputMethodService mTarget;
|
final WeakReference<AbstractInputMethodService> mTarget;
|
||||||
final HandlerCaller mCaller;
|
final HandlerCaller mCaller;
|
||||||
final InputMethod mInputMethod;
|
final WeakReference<InputMethod> mInputMethod;
|
||||||
|
|
||||||
static class Notifier {
|
static class Notifier {
|
||||||
boolean notified;
|
boolean notified;
|
||||||
@@ -96,21 +97,32 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
|
|
||||||
public IInputMethodWrapper(AbstractInputMethodService context,
|
public IInputMethodWrapper(AbstractInputMethodService context,
|
||||||
InputMethod inputMethod) {
|
InputMethod inputMethod) {
|
||||||
mTarget = context;
|
mTarget = new WeakReference<AbstractInputMethodService>(context);
|
||||||
mCaller = new HandlerCaller(context, this);
|
mCaller = new HandlerCaller(context.getApplicationContext(), this);
|
||||||
mInputMethod = inputMethod;
|
mInputMethod = new WeakReference<InputMethod>(inputMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputMethod getInternalInputMethod() {
|
public InputMethod getInternalInputMethod() {
|
||||||
return mInputMethod;
|
return mInputMethod.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeMessage(Message msg) {
|
public void executeMessage(Message msg) {
|
||||||
|
InputMethod inputMethod = mInputMethod.get();
|
||||||
|
// Need a valid reference to the inputMethod for everything except a dump.
|
||||||
|
if (inputMethod == null && msg.what != DO_DUMP) {
|
||||||
|
Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case DO_DUMP: {
|
case DO_DUMP: {
|
||||||
|
AbstractInputMethodService target = mTarget.get();
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
|
HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
|
||||||
try {
|
try {
|
||||||
mTarget.dump((FileDescriptor)args.arg1,
|
target.dump((FileDescriptor)args.arg1,
|
||||||
(PrintWriter)args.arg2, (String[])args.arg3);
|
(PrintWriter)args.arg2, (String[])args.arg3);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
((PrintWriter)args.arg2).println("Exception: " + e);
|
((PrintWriter)args.arg2).println("Exception: " + e);
|
||||||
@@ -122,22 +134,22 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
case DO_ATTACH_TOKEN: {
|
case DO_ATTACH_TOKEN: {
|
||||||
mInputMethod.attachToken((IBinder)msg.obj);
|
inputMethod.attachToken((IBinder)msg.obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DO_SET_INPUT_CONTEXT: {
|
case DO_SET_INPUT_CONTEXT: {
|
||||||
mInputMethod.bindInput((InputBinding)msg.obj);
|
inputMethod.bindInput((InputBinding)msg.obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DO_UNSET_INPUT_CONTEXT:
|
case DO_UNSET_INPUT_CONTEXT:
|
||||||
mInputMethod.unbindInput();
|
inputMethod.unbindInput();
|
||||||
return;
|
return;
|
||||||
case DO_START_INPUT: {
|
case DO_START_INPUT: {
|
||||||
HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
|
HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
|
||||||
IInputContext inputContext = (IInputContext)args.arg1;
|
IInputContext inputContext = (IInputContext)args.arg1;
|
||||||
InputConnection ic = inputContext != null
|
InputConnection ic = inputContext != null
|
||||||
? new InputConnectionWrapper(inputContext) : null;
|
? new InputConnectionWrapper(inputContext) : null;
|
||||||
mInputMethod.startInput(ic, (EditorInfo)args.arg2);
|
inputMethod.startInput(ic, (EditorInfo)args.arg2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DO_RESTART_INPUT: {
|
case DO_RESTART_INPUT: {
|
||||||
@@ -145,33 +157,37 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
IInputContext inputContext = (IInputContext)args.arg1;
|
IInputContext inputContext = (IInputContext)args.arg1;
|
||||||
InputConnection ic = inputContext != null
|
InputConnection ic = inputContext != null
|
||||||
? new InputConnectionWrapper(inputContext) : null;
|
? new InputConnectionWrapper(inputContext) : null;
|
||||||
mInputMethod.restartInput(ic, (EditorInfo)args.arg2);
|
inputMethod.restartInput(ic, (EditorInfo)args.arg2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DO_CREATE_SESSION: {
|
case DO_CREATE_SESSION: {
|
||||||
mInputMethod.createSession(new InputMethodSessionCallbackWrapper(
|
inputMethod.createSession(new InputMethodSessionCallbackWrapper(
|
||||||
mCaller.mContext, (IInputMethodCallback)msg.obj));
|
mCaller.mContext, (IInputMethodCallback)msg.obj));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DO_SET_SESSION_ENABLED:
|
case DO_SET_SESSION_ENABLED:
|
||||||
mInputMethod.setSessionEnabled((InputMethodSession)msg.obj,
|
inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
|
||||||
msg.arg1 != 0);
|
msg.arg1 != 0);
|
||||||
return;
|
return;
|
||||||
case DO_REVOKE_SESSION:
|
case DO_REVOKE_SESSION:
|
||||||
mInputMethod.revokeSession((InputMethodSession)msg.obj);
|
inputMethod.revokeSession((InputMethodSession)msg.obj);
|
||||||
return;
|
return;
|
||||||
case DO_SHOW_SOFT_INPUT:
|
case DO_SHOW_SOFT_INPUT:
|
||||||
mInputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
|
inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
|
||||||
return;
|
return;
|
||||||
case DO_HIDE_SOFT_INPUT:
|
case DO_HIDE_SOFT_INPUT:
|
||||||
mInputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
|
inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.w(TAG, "Unhandled message code: " + msg.what);
|
Log.w(TAG, "Unhandled message code: " + msg.what);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
|
@Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
|
||||||
if (mTarget.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
AbstractInputMethodService target = mTarget.get();
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
fout.println("Permission Denial: can't dump InputMethodManager from from pid="
|
fout.println("Permission Denial: can't dump InputMethodManager from from pid="
|
||||||
|
|||||||
@@ -48,4 +48,6 @@ oneway interface IInputMethodSession {
|
|||||||
void appPrivateCommand(String action, in Bundle data);
|
void appPrivateCommand(String action, in Bundle data);
|
||||||
|
|
||||||
void toggleSoftInput(int showFlags, int hideFlags);
|
void toggleSoftInput(int showFlags, int hideFlags);
|
||||||
|
|
||||||
|
void finishSession();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -890,12 +890,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void finishSession(SessionState sessionState) {
|
||||||
|
if (sessionState != null && sessionState.session != null) {
|
||||||
|
try {
|
||||||
|
sessionState.session.finishSession();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Session failed to close due to remote exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clearCurMethodLocked() {
|
void clearCurMethodLocked() {
|
||||||
if (mCurMethod != null) {
|
if (mCurMethod != null) {
|
||||||
for (ClientState cs : mClients.values()) {
|
for (ClientState cs : mClients.values()) {
|
||||||
cs.sessionRequested = false;
|
cs.sessionRequested = false;
|
||||||
|
finishSession(cs.curSession);
|
||||||
cs.curSession = null;
|
cs.curSession = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finishSession(mEnabledSession);
|
||||||
|
mEnabledSession = null;
|
||||||
mCurMethod = null;
|
mCurMethod = null;
|
||||||
}
|
}
|
||||||
mStatusBar.setIconVisibility(mInputMethodIcon, false);
|
mStatusBar.setIconVisibility(mInputMethodIcon, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user