summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Justin Ghan <justinghan@google.com> 2024-02-08 00:37:03 -0800
committer Justin Ghan <justinghan@google.com> 2024-02-13 07:00:53 +0000
commita72c67178c44b296d4ebe44e0758a900c97b1496 (patch)
tree8e9ab89815db01c4424611d523422d457df046c7
parentc1e1505e585e2ded92a809fb9289550dbac40582 (diff)
Add connectionless handwriting support to input method info
Adds APIs for input methods to declare support for connectionless handwriting sessions, and APIs to query support. Bug: 300979854 Bug: 293898187 Test: atest InputMethodInfoTest Test: atest StylusHandwritingTest Change-Id: I16ff508187c9b08146f56801bf3a83fbc2aade73
-rw-r--r--core/api/current.txt3
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java5
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java35
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java44
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/res/res/values/attrs.xml20
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java17
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java10
10 files changed, 129 insertions, 11 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 076f016b6914..797f2553135e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1603,6 +1603,7 @@ package android {
field public static final int supportedTypes = 16844369; // 0x1010651
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsBatteryGameMode = 16844374; // 0x1010656
+ field @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public static final int supportsConnectionlessStylusHandwriting;
field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
field public static final int supportsInlineSuggestionsWithTouchExploration = 16844397; // 0x101066d
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
@@ -56105,6 +56106,7 @@ package android.view.inputmethod {
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public CharSequence loadLabel(android.content.pm.PackageManager);
method public boolean shouldShowInInputMethodPicker();
+ method @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public boolean supportsConnectionlessStylusHandwriting();
method public boolean supportsStylusHandwriting();
method public boolean suppressesSpellChecker();
method public void writeToParcel(android.os.Parcel, int);
@@ -56134,6 +56136,7 @@ package android.view.inputmethod {
method public boolean isAcceptingText();
method public boolean isActive(android.view.View);
method public boolean isActive();
+ method @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public boolean isConnectionlessStylusHandwritingAvailable();
method public boolean isFullscreenMode();
method public boolean isInputMethodSuppressingSpellChecker();
method public boolean isStylusHandwritingAvailable();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index dd79c4a40cba..5b9032241349 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3901,7 +3901,7 @@ package android.view.inputmethod {
}
public final class InputMethodInfo implements android.os.Parcelable {
- ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String);
+ ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String);
ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8
field public static final int MAX_IMES_PER_PACKAGE = 20; // 0x14
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index 89da04128bc8..474c61f0abbb 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -530,13 +530,14 @@ final class IInputMethodManagerGlobalInvoker {
@AnyThread
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
- static boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
+ static boolean isStylusHandwritingAvailableAsUser(
+ @UserIdInt int userId, boolean connectionless) {
final IInputMethodManager service = getService();
if (service == null) {
return false;
}
try {
- return service.isStylusHandwritingAvailableAsUser(userId);
+ return service.isStylusHandwritingAvailableAsUser(userId, connectionless);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index b60efc1ee508..7c9678f11e0e 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -204,6 +204,9 @@ public final class InputMethodInfo implements Parcelable {
*/
private final boolean mSupportsStylusHandwriting;
+ /** The flag whether this IME supports connectionless stylus handwriting sessions. */
+ private final boolean mSupportsConnectionlessStylusHandwriting;
+
/**
* The stylus handwriting setting activity's name, used by the system settings to
* launch the stylus handwriting specific setting activity of this input method.
@@ -330,6 +333,9 @@ public final class InputMethodInfo implements Parcelable {
com.android.internal.R.styleable.InputMethod_configChanges, 0);
mSupportsStylusHandwriting = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsStylusHandwriting, false);
+ mSupportsConnectionlessStylusHandwriting = sa.getBoolean(
+ com.android.internal.R.styleable
+ .InputMethod_supportsConnectionlessStylusHandwriting, false);
stylusHandwritingSettingsActivity = sa.getString(
com.android.internal.R.styleable.InputMethod_stylusHandwritingSettingsActivity);
sa.recycle();
@@ -442,6 +448,7 @@ public final class InputMethodInfo implements Parcelable {
mSubtypes = source.mSubtypes;
mHandledConfigChanges = source.mHandledConfigChanges;
mSupportsStylusHandwriting = source.mSupportsStylusHandwriting;
+ mSupportsConnectionlessStylusHandwriting = source.mSupportsConnectionlessStylusHandwriting;
mForceDefault = source.mForceDefault;
mStylusHandwritingSettingsActivityAttr = source.mStylusHandwritingSettingsActivityAttr;
}
@@ -463,6 +470,7 @@ public final class InputMethodInfo implements Parcelable {
mSubtypes = new InputMethodSubtypeArray(source);
mHandledConfigChanges = source.readInt();
mSupportsStylusHandwriting = source.readBoolean();
+ mSupportsConnectionlessStylusHandwriting = source.readBoolean();
mStylusHandwritingSettingsActivityAttr = source.readString8();
mForceDefault = false;
}
@@ -479,6 +487,7 @@ public final class InputMethodInfo implements Parcelable {
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
false /* supportsStylusHandwriting */,
+ false /* supportConnectionlessStylusHandwriting */,
null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -488,9 +497,11 @@ public final class InputMethodInfo implements Parcelable {
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
public InputMethodInfo(@NonNull String packageName, @NonNull String className,
@NonNull CharSequence label, @NonNull String settingsActivity,
@NonNull String languageSettingsActivity, boolean supportStylusHandwriting,
+ boolean supportConnectionlessStylusHandwriting,
@NonNull String stylusHandwritingSettingsActivityAttr) {
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, languageSettingsActivity, null /* subtypes */,
@@ -498,8 +509,8 @@ public final class InputMethodInfo implements Parcelable {
true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
- supportStylusHandwriting, stylusHandwritingSettingsActivityAttr,
- false /* inlineSuggestionsEnabled */);
+ supportStylusHandwriting, supportConnectionlessStylusHandwriting,
+ stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
}
/**
@@ -517,6 +528,7 @@ public final class InputMethodInfo implements Parcelable {
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
false /* isVirtualDeviceOnly */, handledConfigChanges,
false /* supportsStylusHandwriting */,
+ false /* supportConnectionlessStylusHandwriting */,
null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -533,6 +545,7 @@ public final class InputMethodInfo implements Parcelable {
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
false /* isVrOnly */, false /* isVirtualDeviceOnly */, 0 /* handledconfigChanges */,
false /* supportsStylusHandwriting */,
+ false /* supportConnectionlessStylusHandwriting */,
null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -549,6 +562,7 @@ public final class InputMethodInfo implements Parcelable {
supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
false /* isVirtualDeviceOnly */,
0 /* handledConfigChanges */, false /* supportsStylusHandwriting */,
+ false /* supportConnectionlessStylusHandwriting */,
null /* stylusHandwritingSettingsActivityAttr */,
false /* inlineSuggestionsEnabled */);
}
@@ -562,7 +576,8 @@ public final class InputMethodInfo implements Parcelable {
int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
boolean isVrOnly, boolean isVirtualDeviceOnly, int handledConfigChanges,
- boolean supportsStylusHandwriting, String stylusHandwritingSettingsActivityAttr,
+ boolean supportsStylusHandwriting, boolean supportsConnectionlessStylusHandwriting,
+ String stylusHandwritingSettingsActivityAttr,
boolean supportsInlineSuggestionsWithTouchExploration) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
@@ -583,6 +598,7 @@ public final class InputMethodInfo implements Parcelable {
mIsVirtualDeviceOnly = isVirtualDeviceOnly;
mHandledConfigChanges = handledConfigChanges;
mSupportsStylusHandwriting = supportsStylusHandwriting;
+ mSupportsConnectionlessStylusHandwriting = supportsConnectionlessStylusHandwriting;
mStylusHandwritingSettingsActivityAttr = stylusHandwritingSettingsActivityAttr;
}
@@ -763,6 +779,16 @@ public final class InputMethodInfo implements Parcelable {
}
/**
+ * Returns whether the IME supports connectionless stylus handwriting sessions.
+ *
+ * @attr ref android.R.styleable#InputMethod_supportsConnectionlessStylusHandwriting
+ */
+ @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
+ public boolean supportsConnectionlessStylusHandwriting() {
+ return mSupportsConnectionlessStylusHandwriting;
+ }
+
+ /**
* Returns {@link Intent} for stylus handwriting settings activity with
* {@link Intent#getAction() Intent action} {@link #ACTION_STYLUS_HANDWRITING_SETTINGS}
* if IME {@link #supportsStylusHandwriting() supports stylus handwriting}, else
@@ -828,6 +854,8 @@ public final class InputMethodInfo implements Parcelable {
+ " mSuppressesSpellChecker=" + mSuppressesSpellChecker
+ " mShowInInputMethodPicker=" + mShowInInputMethodPicker
+ " mSupportsStylusHandwriting=" + mSupportsStylusHandwriting
+ + " mSupportsConnectionlessStylusHandwriting="
+ + mSupportsConnectionlessStylusHandwriting
+ " mStylusHandwritingSettingsActivityAttr="
+ mStylusHandwritingSettingsActivityAttr);
pw.println(prefix + "mIsDefaultResId=0x"
@@ -947,6 +975,7 @@ public final class InputMethodInfo implements Parcelable {
mSubtypes.writeToParcel(dest);
dest.writeInt(mHandledConfigChanges);
dest.writeBoolean(mSupportsStylusHandwriting);
+ dest.writeBoolean(mSupportsConnectionlessStylusHandwriting);
dest.writeString8(mStylusHandwritingSettingsActivityAttr);
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3b07f27dc95a..6772efb27d06 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -566,8 +566,15 @@ public final class InputMethodManager {
@GuardedBy("mH")
private PropertyInvalidatedCache<Integer, Boolean> mStylusHandwritingAvailableCache;
+ /** Cached value for {@link #isConnectionlessStylusHandwritingAvailable} for userId. */
+ @GuardedBy("mH")
+ private PropertyInvalidatedCache<Integer, Boolean>
+ mConnectionlessStylusHandwritingAvailableCache;
+
private static final String CACHE_KEY_STYLUS_HANDWRITING_PROPERTY =
"cache_key.system_server.stylus_handwriting";
+ private static final String CACHE_KEY_CONNECTIONLESS_STYLUS_HANDWRITING_PROPERTY =
+ "cache_key.system_server.connectionless_stylus_handwriting";
@GuardedBy("mH")
private int mCursorSelStart;
@@ -691,6 +698,17 @@ public final class InputMethodManager {
PropertyInvalidatedCache.invalidateCache(CACHE_KEY_STYLUS_HANDWRITING_PROPERTY);
}
+ /**
+ * Calling this will invalidate the local connectionless stylus handwriting availability cache,
+ * which forces the next query in any process to recompute the cache.
+ *
+ * @hide
+ */
+ public static void invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches() {
+ PropertyInvalidatedCache.invalidateCache(
+ CACHE_KEY_CONNECTIONLESS_STYLUS_HANDWRITING_PROPERTY);
+ }
+
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
return afm != null && afm.isAutofillUiShowing();
@@ -1584,7 +1602,7 @@ public final class InputMethodManager {
@Override
public Boolean recompute(Integer userId) {
return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(
- userId);
+ userId, /* connectionless= */ false);
}
};
}
@@ -1594,6 +1612,30 @@ public final class InputMethodManager {
}
/**
+ * Returns {@code true} if the currently selected IME supports connectionless stylus handwriting
+ * sessions and is enabled.
+ */
+ @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
+ public boolean isConnectionlessStylusHandwritingAvailable() {
+ if (ActivityThread.currentApplication() == null) {
+ return false;
+ }
+ synchronized (mH) {
+ if (mConnectionlessStylusHandwritingAvailableCache == null) {
+ mConnectionlessStylusHandwritingAvailableCache = new PropertyInvalidatedCache<>(
+ /* maxEntries= */ 4, CACHE_KEY_CONNECTIONLESS_STYLUS_HANDWRITING_PROPERTY) {
+ @Override
+ public Boolean recompute(@NonNull Integer userId) {
+ return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(
+ userId, /* connectionless= */ true);
+ }
+ };
+ }
+ return mConnectionlessStylusHandwritingAvailableCache.query(UserHandle.myUserId());
+ }
+ }
+
+ /**
* Returns the list of installed input methods for the specified user.
*
* <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 595bf3b8eb97..ca5d44111f74 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -158,7 +158,7 @@ interface IInputMethodManager {
/** Returns {@code true} if currently selected IME supports Stylus handwriting. */
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
- boolean isStylusHandwritingAvailableAsUser(int userId);
+ boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless);
/** add virtual stylus id for test Stylus handwriting session **/
@EnforcePermission("TEST_INPUT_METHOD")
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3cd18939e2ca..321f9f9de457 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3978,6 +3978,26 @@
{@link android.inputmethodservice.InputMethodService#onFinishInput()}.
-->
<attr name="supportsStylusHandwriting" format="boolean" />
+ <!-- Specifies whether the IME supports connectionless stylus handwriting sessions. A
+ connectionless session differs from a regular session in that the IME does not use an
+ input connection to communicate with a text editor. Instead, the IME directly returns
+ recognised handwritten text via an {@link
+ android.inputmethodservice.InputMethodService} handwriting lifecycle API.
+
+ <p>If the IME supports connectionless sessions, apps or framework may start a
+ connectionless session when a stylus motion event sequence begins. {@link
+ android.inputmethodservice.InputMethodService#onStartConnectionlessStylusHandwriting}
+ is called. If the IME is ready for stylus input, it should return {code true} to start
+ the basic mode session. As in the regular session, the IME will receive stylus motion
+ events to the stylus handwriting window and should render ink to a view in this window.
+ When the user has stopped handwriting, the IME should end the session and deliver the
+ result by calling {@link
+ android.inputmethodservice.InputMethodService#finishConnectionlessStylusHandwriting}.
+
+ The default value is {code false}. If {code true}, {@link
+ android.R.attr#supportsStylusHandwriting} should also be {code true}.
+ -->
+ <attr name="supportsConnectionlessStylusHandwriting" format="boolean" />
<!-- Class name of an activity that allows the user to modify the stylus handwriting
settings for this service -->
<attr name="stylusHandwritingSettingsActivity" format="string" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 56743908e281..6029d2377cdc 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -157,6 +157,8 @@
<public name="useLocalePreferredLineHeightForMinimum"/>
<!-- @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") -->
<public name="contentSensitivity" />
+ <!-- @FlaggedApi("android.view.inputmethod.connectionless_handwriting") -->
+ <public name="supportsConnectionlessStylusHandwriting" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index c8c0482f5a9d..a100fe06c407 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -77,6 +77,7 @@ final class InputMethodBindingController {
@GuardedBy("ImfLock.class") private int mCurSeq;
@GuardedBy("ImfLock.class") private boolean mVisibleBound;
@GuardedBy("ImfLock.class") private boolean mSupportsStylusHw;
+ @GuardedBy("ImfLock.class") private boolean mSupportsConnectionlessStylusHw;
@Nullable private CountDownLatch mLatchForTesting;
@@ -243,10 +244,17 @@ final class InputMethodBindingController {
/**
* Returns {@code true} if current IME supports Stylus Handwriting.
*/
+ @GuardedBy("ImfLock.class")
boolean supportsStylusHandwriting() {
return mSupportsStylusHw;
}
+ /** Returns whether the current IME supports connectionless stylus handwriting sessions. */
+ @GuardedBy("ImfLock.class")
+ boolean supportsConnectionlessStylusHandwriting() {
+ return mSupportsConnectionlessStylusHw;
+ }
+
/**
* Used to bring IME service up to visible adjustment while it is being shown.
*/
@@ -298,6 +306,15 @@ final class InputMethodBindingController {
if (supportsStylusHwChanged) {
InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
}
+ boolean supportsConnectionlessStylusHwChanged =
+ mSupportsConnectionlessStylusHw
+ != info.supportsConnectionlessStylusHandwriting();
+ if (supportsConnectionlessStylusHwChanged) {
+ mSupportsConnectionlessStylusHw =
+ info.supportsConnectionlessStylusHandwriting();
+ InputMethodManager
+ .invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches();
+ }
mService.initializeImeLocked(mCurMethod, mCurToken);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 96c0c8a9a7b8..8f8993bd44d3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1980,7 +1980,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
+ public boolean isStylusHandwritingAvailableAsUser(
+ @UserIdInt int userId, boolean connectionless) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
@@ -1993,14 +1994,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// Check if selected IME of current user supports handwriting.
if (userId == mSettings.getUserId()) {
- return mBindingController.supportsStylusHandwriting();
+ return mBindingController.supportsStylusHandwriting()
+ && (!connectionless
+ || mBindingController.supportsConnectionlessStylusHandwriting());
}
//TODO(b/197848765): This can be optimized by caching multi-user methodMaps/methodList.
//TODO(b/210039666): use cache.
final InputMethodSettings settings = queryMethodMapForUser(userId);
final InputMethodInfo imi = settings.getMethodMap().get(
settings.getSelectedInputMethod());
- return imi != null && imi.supportsStylusHandwriting();
+ return imi != null && imi.supportsStylusHandwriting()
+ && (!connectionless || imi.supportsConnectionlessStylusHandwriting());
}
}