From f149ca784dd09bd97bd479ae254935ff3edaa617 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Mon, 28 Nov 2016 15:54:55 +0000 Subject: [PATCH] Override TextServicesManager in layoutlib When a TextServicesManger is required in layoutlib, provide a fake one. Test: Run layoutlib tests Change-Id: I8c25f4919a2e97b56f705b59747e81cb6f45b07b --- .../bridge/src/android/os/ServiceManager.java | 2 +- .../view/textservice/TextServicesManager.java | 342 ++++++++++++++++++ .../ITextServicesManager_Stub_Delegate.java | 111 ------ .../tools/layoutlib/create/CreateInfo.java | 2 +- 4 files changed, 344 insertions(+), 113 deletions(-) create mode 100644 tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java delete mode 100644 tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java index c96d2ca4c4359..34c78455f85da 100644 --- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java +++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java @@ -34,7 +34,7 @@ public final class ServiceManager { * Is not supposed to return null, but that is fine for layoutlib. */ public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException { - return null; + throw new ServiceNotFoundException(name); } /** diff --git a/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java new file mode 100644 index 0000000000000..06874bd57d2bf --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textservice; + +import com.android.internal.textservice.ISpellCheckerSessionListener; +import com.android.internal.textservice.ITextServicesManager; +import com.android.internal.textservice.ITextServicesSessionListener; + +import android.content.Context; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener; + +import java.util.Locale; + +/** + * System API to the overall text services, which arbitrates interaction between applications + * and text services. You can retrieve an instance of this interface with + * {@link Context#getSystemService(String) Context.getSystemService()}. + * + * The user can change the current text services in Settings. And also applications can specify + * the target text services. + * + *

Architecture Overview

+ * + *

There are three primary parties involved in the text services + * framework (TSF) architecture:

+ * + * + * + *

Text services sessions

+ * + * + */ +public final class TextServicesManager { + private static final String TAG = TextServicesManager.class.getSimpleName(); + private static final boolean DBG = false; + + private static TextServicesManager sInstance; + + private final ITextServicesManager mService; + + private TextServicesManager() { + mService = new FakeTextServicesManager(); + } + + /** + * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist. + * @hide + */ + public static TextServicesManager getInstance() { + synchronized (TextServicesManager.class) { + if (sInstance == null) { + sInstance = new TextServicesManager(); + } + return sInstance; + } + } + + /** + * Returns the language component of a given locale string. + */ + private static String parseLanguageFromLocaleString(String locale) { + final int idx = locale.indexOf('_'); + if (idx < 0) { + return locale; + } else { + return locale.substring(0, idx); + } + } + + /** + * Get a spell checker session for the specified spell checker + * @param locale the locale for the spell checker. If {@code locale} is null and + * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be + * returned. If {@code locale} is not null and referToSpellCheckerLanguageSettings is true, + * the locale specified in Settings will be returned only when it is same as {@code locale}. + * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@code locale} is + * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be + * selected. + * @param listener a spell checker session lister for getting results from a spell checker. + * @param referToSpellCheckerLanguageSettings if true, the session for one of enabled + * languages in settings will be returned. + * @return the spell checker session of the spell checker + */ + public SpellCheckerSession newSpellCheckerSession(Bundle bundle, Locale locale, + SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) { + if (listener == null) { + throw new NullPointerException(); + } + if (!referToSpellCheckerLanguageSettings && locale == null) { + throw new IllegalArgumentException("Locale should not be null if you don't refer" + + " settings."); + } + + if (referToSpellCheckerLanguageSettings && !isSpellCheckerEnabled()) { + return null; + } + + final SpellCheckerInfo sci; + try { + sci = mService.getCurrentSpellChecker(null); + } catch (RemoteException e) { + return null; + } + if (sci == null) { + return null; + } + SpellCheckerSubtype subtypeInUse = null; + if (referToSpellCheckerLanguageSettings) { + subtypeInUse = getCurrentSpellCheckerSubtype(true); + if (subtypeInUse == null) { + return null; + } + if (locale != null) { + final String subtypeLocale = subtypeInUse.getLocale(); + final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale); + if (subtypeLanguage.length() < 2 || !locale.getLanguage().equals(subtypeLanguage)) { + return null; + } + } + } else { + final String localeStr = locale.toString(); + for (int i = 0; i < sci.getSubtypeCount(); ++i) { + final SpellCheckerSubtype subtype = sci.getSubtypeAt(i); + final String tempSubtypeLocale = subtype.getLocale(); + final String tempSubtypeLanguage = parseLanguageFromLocaleString(tempSubtypeLocale); + if (tempSubtypeLocale.equals(localeStr)) { + subtypeInUse = subtype; + break; + } else if (tempSubtypeLanguage.length() >= 2 && + locale.getLanguage().equals(tempSubtypeLanguage)) { + subtypeInUse = subtype; + } + } + } + if (subtypeInUse == null) { + return null; + } + final SpellCheckerSession session = new SpellCheckerSession( + sci, mService, listener, subtypeInUse); + try { + mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(), + session.getTextServicesSessionListener(), + session.getSpellCheckerSessionListener(), bundle); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return session; + } + + /** + * @hide + */ + public SpellCheckerInfo[] getEnabledSpellCheckers() { + try { + final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(); + if (DBG) { + Log.d(TAG, "getEnabledSpellCheckers: " + (retval != null ? retval.length : "null")); + } + return retval; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public SpellCheckerInfo getCurrentSpellChecker() { + try { + // Passing null as a locale for ICS + return mService.getCurrentSpellChecker(null); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void setCurrentSpellChecker(SpellCheckerInfo sci) { + try { + if (sci == null) { + throw new NullPointerException("SpellCheckerInfo is null."); + } + mService.setCurrentSpellChecker(null, sci.getId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public SpellCheckerSubtype getCurrentSpellCheckerSubtype( + boolean allowImplicitlySelectedSubtype) { + try { + // Passing null as a locale until we support multiple enabled spell checker subtypes. + return mService.getCurrentSpellCheckerSubtype(null, allowImplicitlySelectedSubtype); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void setSpellCheckerSubtype(SpellCheckerSubtype subtype) { + try { + final int hashCode; + if (subtype == null) { + hashCode = 0; + } else { + hashCode = subtype.hashCode(); + } + mService.setCurrentSpellCheckerSubtype(null, hashCode); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void setSpellCheckerEnabled(boolean enabled) { + try { + mService.setSpellCheckerEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public boolean isSpellCheckerEnabled() { + try { + return mService.isSpellCheckerEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static class FakeTextServicesManager implements ITextServicesManager { + + @Override + public void finishSpellCheckerService(ISpellCheckerSessionListener arg0) + throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException { + // TODO Auto-generated method stub + return null; + } + + @Override + public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1) + throws RemoteException { + // TODO Auto-generated method stub + return null; + } + + @Override + public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void getSpellCheckerService(String arg0, String arg1, + ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4) + throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public boolean isSpellCheckerEnabled() throws RemoteException { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public void setSpellCheckerEnabled(boolean arg0) throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public IBinder asBinder() { + // TODO Auto-generated method stub + return null; + } + + } +} \ No newline at end of file diff --git a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java deleted file mode 100644 index 3017292d8337f..0000000000000 --- a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.textservice; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.view.textservice.SpellCheckerInfo; -import android.view.textservice.SpellCheckerSubtype; - - -/** - * Delegate used to provide new implementation of a select few methods of - * {@link ITextServicesManager$Stub} - * - * Through the layoutlib_create tool, the original methods of Stub have been replaced - * by calls to methods of the same name in this delegate class. - * - */ -public class ITextServicesManager_Stub_Delegate { - - @LayoutlibDelegate - public static ITextServicesManager asInterface(IBinder obj) { - // ignore the obj and return a fake interface implementation - return new FakeTextServicesManager(); - } - - private static class FakeTextServicesManager implements ITextServicesManager { - - @Override - public void finishSpellCheckerService(ISpellCheckerSessionListener arg0) - throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException { - // TODO Auto-generated method stub - return null; - } - - @Override - public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1) - throws RemoteException { - // TODO Auto-generated method stub - return null; - } - - @Override - public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException { - // TODO Auto-generated method stub - return null; - } - - @Override - public void getSpellCheckerService(String arg0, String arg1, - ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4) - throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public boolean isSpellCheckerEnabled() throws RemoteException { - // TODO Auto-generated method stub - return false; - } - - @Override - public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public void setSpellCheckerEnabled(boolean arg0) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public IBinder asBinder() { - // TODO Auto-generated method stub - return null; - } - - } - } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index b7d08f2c1556b..a23bad6ed4802 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -235,7 +235,6 @@ public final class CreateInfo implements ICreateInfo { "android.view.ViewGroup#drawChild", "com.android.internal.view.menu.MenuBuilder#createNewMenuItem", "com.android.internal.util.XmlUtils#convertValueToInt", - "com.android.internal.textservice.ITextServicesManager$Stub#asInterface", "dalvik.system.VMRuntime#newUnpaddedArray", "libcore.io.MemoryMappedFile#mmapRO", "libcore.io.MemoryMappedFile#close", @@ -304,6 +303,7 @@ public final class CreateInfo implements ICreateInfo { private final static String[] RENAMED_CLASSES = new String[] { "android.os.ServiceManager", "android.os._Original_ServiceManager", + "android.view.textservice.TextServicesManager", "android.view.textservice._Original_TextServicesManager", "android.util.LruCache", "android.util._Original_LruCache", "android.view.SurfaceView", "android.view._Original_SurfaceView", "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",