Loading core/java/android/database/DatabaseUtils.java +23 −9 Original line number Diff line number Diff line Loading @@ -511,17 +511,31 @@ public class DatabaseUtils { */ public static void appendEscapedSQLString(StringBuilder sb, String sqlString) { sb.append('\''); if (sqlString.indexOf('\'') != -1) { int length = sqlString.length(); for (int i = 0; i < length; i++) { char c = sqlString.charAt(i); if (Character.isHighSurrogate(c)) { if (i == length - 1) { continue; } if (Character.isLowSurrogate(sqlString.charAt(i + 1))) { // add them both sb.append(c); sb.append(sqlString.charAt(i + 1)); continue; } else { // this is a lone surrogate, skip it continue; } } if (Character.isLowSurrogate(c)) { continue; } if (c == '\'') { sb.append('\''); } sb.append(c); } } else sb.append(sqlString); sb.append('\''); } Loading core/java/android/net/Uri.java +17 −19 Original line number Diff line number Diff line Loading @@ -882,10 +882,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { } static Uri readFrom(Parcel parcel) { final StringUri stringUri = new StringUri(parcel.readString8()); return new OpaqueUri( parcel.readString8(), Part.readFrom(parcel), Part.readFrom(parcel) stringUri.parseScheme(), stringUri.getSsp(), stringUri.getFragmentPart() ); } Loading @@ -895,9 +896,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); parcel.writeString8(scheme); ssp.writeTo(parcel); fragment.writeTo(parcel); parcel.writeString8(toString()); } public boolean isHierarchical() { Loading Loading @@ -1196,22 +1195,25 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { Part query, Part fragment) { this.scheme = scheme; this.authority = Part.nonNull(authority); this.path = path == null ? PathPart.NULL : path; this.path = generatePath(path); this.query = Part.nonNull(query); this.fragment = Part.nonNull(fragment); } static Uri readFrom(Parcel parcel) { final String scheme = parcel.readString8(); final Part authority = Part.readFrom(parcel); private PathPart generatePath(PathPart originalPath) { // In RFC3986 the path should be determined based on whether there is a scheme or // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3). final boolean hasSchemeOrAuthority = (scheme != null && scheme.length() > 0) || !authority.isEmpty(); final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel); final Part query = Part.readFrom(parcel); final Part fragment = Part.readFrom(parcel); return new HierarchicalUri(scheme, authority, path, query, fragment); final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath) : originalPath; return newPath == null ? PathPart.NULL : newPath; } static Uri readFrom(Parcel parcel) { final StringUri stringUri = new StringUri(parcel.readString8()); return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(), stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart()); } public int describeContents() { Loading @@ -1220,11 +1222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); parcel.writeString8(scheme); authority.writeTo(parcel); path.writeTo(parcel); query.writeTo(parcel); fragment.writeTo(parcel); parcel.writeString8(toString()); } public boolean isHierarchical() { Loading core/java/android/view/InsetsController.java +32 −33 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.util.function.TriFunction; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading @@ -77,7 +78,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.BiFunction; /** * Implements {@link WindowInsetsController} on the client. Loading Loading @@ -621,7 +621,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final InsetsState mLastDispatchedState = new InsetsState(); private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> mConsumerCreator; private final TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final InsetsSourceConsumer mImeSourceConsumer; private final Host mHost; Loading Loading @@ -689,13 +690,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // Don't change the indexes of the sources while traversing. Remove it later. mPendingRemoveIndexes.add(index1); // Remove the consumer as well except the IME one. IME consumer should always // be there since we need to communicate with InputMethodManager no matter we // have the source or not. if (source1.getType() != ime()) { mSourceConsumers.remove(source1.getId()); } } @Override Loading Loading @@ -750,12 +744,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation }; public InsetsController(Host host) { this(host, (controller, source) -> { if (source.getType() == ime()) { return new ImeInsetsSourceConsumer(source.getId(), controller.mState, this(host, (controller, id, type) -> { if (type == ime()) { return new ImeInsetsSourceConsumer(id, controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(source.getId(), source.getType(), controller.mState, return new InsetsSourceConsumer(id, type, controller.mState, Transaction::new, controller); } }, host.getHandler()); Loading @@ -763,7 +757,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public InsetsController(Host host, BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> consumerCreator, TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mHost = host; mConsumerCreator = consumerCreator; Loading Loading @@ -815,7 +809,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation }; // Make mImeSourceConsumer always non-null. mImeSourceConsumer = getSourceConsumer(new InsetsSource(ID_IME, ime())); mImeSourceConsumer = getSourceConsumer(ID_IME, ime()); } @VisibleForTesting Loading Loading @@ -893,7 +887,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelledUserAnimationTypes[0] |= type; } } getSourceConsumer(source).updateSource(source, animationType); final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId()); if (consumer != null) { consumer.updateSource(source, animationType); } else { mState.addSource(source); } existingTypes |= type; if (source.isVisible()) { visibleTypes |= type; Loading Loading @@ -997,8 +996,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @InsetsType int controllableTypes = 0; int consumedControlCount = 0; final int[] showTypes = new int[1]; final int[] hideTypes = new int[1]; final @InsetsType int[] showTypes = new int[1]; final @InsetsType int[] hideTypes = new int[1]; // Ensure to update all existing source consumers for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { Loading @@ -1014,15 +1013,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation consumer.setControl(control, showTypes, hideTypes); } // Ensure to create source consumers if not available yet. if (consumedControlCount != mTmpControlArray.size()) { // Whoops! The server sent us some controls without sending corresponding sources. for (int i = mTmpControlArray.size() - 1; i >= 0; i--) { final InsetsSourceControl control = mTmpControlArray.valueAt(i); final InsetsSourceConsumer consumer = mSourceConsumers.get(control.getId()); if (consumer == null) { control.release(SurfaceControl::release); Log.e(TAG, control + " has no consumer."); } getSourceConsumer(control.getId(), control.getType()) .setControl(control, showTypes, hideTypes); } } Loading Loading @@ -1587,6 +1583,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (type == ime()) { abortPendingImeControlRequest(); } if (consumer.getType() != ime()) { // IME consumer should always be there since we need to communicate with // InputMethodManager no matter we have the control or not. mSourceConsumers.remove(consumer.getId()); } } private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) { Loading Loading @@ -1640,21 +1641,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } @VisibleForTesting public @NonNull InsetsSourceConsumer getSourceConsumer(InsetsSource source) { final int sourceId = source.getId(); InsetsSourceConsumer consumer = mSourceConsumers.get(sourceId); public @NonNull InsetsSourceConsumer getSourceConsumer(int id, int type) { InsetsSourceConsumer consumer = mSourceConsumers.get(id); if (consumer != null) { return consumer; } if (source.getType() == ime() && mImeSourceConsumer != null) { if (type == ime() && mImeSourceConsumer != null) { // WindowInsets.Type.ime() should be only provided by one source. mSourceConsumers.remove(mImeSourceConsumer.getId()); consumer = mImeSourceConsumer; consumer.setId(sourceId); consumer.setId(id); } else { consumer = mConsumerCreator.apply(this, source); consumer = mConsumerCreator.apply(this, id, type); } mSourceConsumers.put(sourceId, consumer); mSourceConsumers.put(id, consumer); return consumer; } Loading @@ -1663,8 +1663,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return mImeSourceConsumer; } @VisibleForTesting public void notifyVisibilityChanged() { void notifyVisibilityChanged() { mHost.notifyInsetsChanged(); } Loading core/java/android/view/InsetsSourceConsumer.java +6 −3 Original line number Diff line number Diff line Loading @@ -149,9 +149,12 @@ public class InsetsSourceConsumer { // Check if we need to restore server visibility. final InsetsSource localSource = mState.peekSource(mId); final InsetsSource serverSource = mController.getLastDispatchedState().peekSource(mId); if (localSource != null && serverSource != null && localSource.isVisible() != serverSource.isVisible()) { localSource.setVisible(serverSource.isVisible()); final boolean localVisible = localSource != null && localSource.isVisible(); final boolean serverVisible = serverSource != null && serverSource.isVisible(); if (localSource != null) { localSource.setVisible(serverVisible); } if (localVisible != serverVisible) { mController.notifyVisibilityChanged(); } } else { Loading core/jni/android_view_InputDevice.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,13 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi return NULL; } // b/274058082: Pass a copy of the key character map to avoid concurrent // access std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap(); if (map != nullptr) { map = std::make_shared<KeyCharacterMap>(*map); } ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str())); if (!descriptorObj.get()) { Loading @@ -62,7 +69,7 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi ScopedLocalRef<jobject> kcmObj(env, android_view_KeyCharacterMap_create(env, deviceInfo.getId(), deviceInfo.getKeyCharacterMap())); map)); if (!kcmObj.get()) { return NULL; } Loading Loading
core/java/android/database/DatabaseUtils.java +23 −9 Original line number Diff line number Diff line Loading @@ -511,17 +511,31 @@ public class DatabaseUtils { */ public static void appendEscapedSQLString(StringBuilder sb, String sqlString) { sb.append('\''); if (sqlString.indexOf('\'') != -1) { int length = sqlString.length(); for (int i = 0; i < length; i++) { char c = sqlString.charAt(i); if (Character.isHighSurrogate(c)) { if (i == length - 1) { continue; } if (Character.isLowSurrogate(sqlString.charAt(i + 1))) { // add them both sb.append(c); sb.append(sqlString.charAt(i + 1)); continue; } else { // this is a lone surrogate, skip it continue; } } if (Character.isLowSurrogate(c)) { continue; } if (c == '\'') { sb.append('\''); } sb.append(c); } } else sb.append(sqlString); sb.append('\''); } Loading
core/java/android/net/Uri.java +17 −19 Original line number Diff line number Diff line Loading @@ -882,10 +882,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { } static Uri readFrom(Parcel parcel) { final StringUri stringUri = new StringUri(parcel.readString8()); return new OpaqueUri( parcel.readString8(), Part.readFrom(parcel), Part.readFrom(parcel) stringUri.parseScheme(), stringUri.getSsp(), stringUri.getFragmentPart() ); } Loading @@ -895,9 +896,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); parcel.writeString8(scheme); ssp.writeTo(parcel); fragment.writeTo(parcel); parcel.writeString8(toString()); } public boolean isHierarchical() { Loading Loading @@ -1196,22 +1195,25 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { Part query, Part fragment) { this.scheme = scheme; this.authority = Part.nonNull(authority); this.path = path == null ? PathPart.NULL : path; this.path = generatePath(path); this.query = Part.nonNull(query); this.fragment = Part.nonNull(fragment); } static Uri readFrom(Parcel parcel) { final String scheme = parcel.readString8(); final Part authority = Part.readFrom(parcel); private PathPart generatePath(PathPart originalPath) { // In RFC3986 the path should be determined based on whether there is a scheme or // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3). final boolean hasSchemeOrAuthority = (scheme != null && scheme.length() > 0) || !authority.isEmpty(); final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel); final Part query = Part.readFrom(parcel); final Part fragment = Part.readFrom(parcel); return new HierarchicalUri(scheme, authority, path, query, fragment); final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath) : originalPath; return newPath == null ? PathPart.NULL : newPath; } static Uri readFrom(Parcel parcel) { final StringUri stringUri = new StringUri(parcel.readString8()); return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(), stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart()); } public int describeContents() { Loading @@ -1220,11 +1222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); parcel.writeString8(scheme); authority.writeTo(parcel); path.writeTo(parcel); query.writeTo(parcel); fragment.writeTo(parcel); parcel.writeString8(toString()); } public boolean isHierarchical() { Loading
core/java/android/view/InsetsController.java +32 −33 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.util.function.TriFunction; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading @@ -77,7 +78,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.BiFunction; /** * Implements {@link WindowInsetsController} on the client. Loading Loading @@ -621,7 +621,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final InsetsState mLastDispatchedState = new InsetsState(); private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> mConsumerCreator; private final TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final InsetsSourceConsumer mImeSourceConsumer; private final Host mHost; Loading Loading @@ -689,13 +690,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // Don't change the indexes of the sources while traversing. Remove it later. mPendingRemoveIndexes.add(index1); // Remove the consumer as well except the IME one. IME consumer should always // be there since we need to communicate with InputMethodManager no matter we // have the source or not. if (source1.getType() != ime()) { mSourceConsumers.remove(source1.getId()); } } @Override Loading Loading @@ -750,12 +744,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation }; public InsetsController(Host host) { this(host, (controller, source) -> { if (source.getType() == ime()) { return new ImeInsetsSourceConsumer(source.getId(), controller.mState, this(host, (controller, id, type) -> { if (type == ime()) { return new ImeInsetsSourceConsumer(id, controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(source.getId(), source.getType(), controller.mState, return new InsetsSourceConsumer(id, type, controller.mState, Transaction::new, controller); } }, host.getHandler()); Loading @@ -763,7 +757,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public InsetsController(Host host, BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> consumerCreator, TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mHost = host; mConsumerCreator = consumerCreator; Loading Loading @@ -815,7 +809,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation }; // Make mImeSourceConsumer always non-null. mImeSourceConsumer = getSourceConsumer(new InsetsSource(ID_IME, ime())); mImeSourceConsumer = getSourceConsumer(ID_IME, ime()); } @VisibleForTesting Loading Loading @@ -893,7 +887,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelledUserAnimationTypes[0] |= type; } } getSourceConsumer(source).updateSource(source, animationType); final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId()); if (consumer != null) { consumer.updateSource(source, animationType); } else { mState.addSource(source); } existingTypes |= type; if (source.isVisible()) { visibleTypes |= type; Loading Loading @@ -997,8 +996,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @InsetsType int controllableTypes = 0; int consumedControlCount = 0; final int[] showTypes = new int[1]; final int[] hideTypes = new int[1]; final @InsetsType int[] showTypes = new int[1]; final @InsetsType int[] hideTypes = new int[1]; // Ensure to update all existing source consumers for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { Loading @@ -1014,15 +1013,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation consumer.setControl(control, showTypes, hideTypes); } // Ensure to create source consumers if not available yet. if (consumedControlCount != mTmpControlArray.size()) { // Whoops! The server sent us some controls without sending corresponding sources. for (int i = mTmpControlArray.size() - 1; i >= 0; i--) { final InsetsSourceControl control = mTmpControlArray.valueAt(i); final InsetsSourceConsumer consumer = mSourceConsumers.get(control.getId()); if (consumer == null) { control.release(SurfaceControl::release); Log.e(TAG, control + " has no consumer."); } getSourceConsumer(control.getId(), control.getType()) .setControl(control, showTypes, hideTypes); } } Loading Loading @@ -1587,6 +1583,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (type == ime()) { abortPendingImeControlRequest(); } if (consumer.getType() != ime()) { // IME consumer should always be there since we need to communicate with // InputMethodManager no matter we have the control or not. mSourceConsumers.remove(consumer.getId()); } } private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) { Loading Loading @@ -1640,21 +1641,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } @VisibleForTesting public @NonNull InsetsSourceConsumer getSourceConsumer(InsetsSource source) { final int sourceId = source.getId(); InsetsSourceConsumer consumer = mSourceConsumers.get(sourceId); public @NonNull InsetsSourceConsumer getSourceConsumer(int id, int type) { InsetsSourceConsumer consumer = mSourceConsumers.get(id); if (consumer != null) { return consumer; } if (source.getType() == ime() && mImeSourceConsumer != null) { if (type == ime() && mImeSourceConsumer != null) { // WindowInsets.Type.ime() should be only provided by one source. mSourceConsumers.remove(mImeSourceConsumer.getId()); consumer = mImeSourceConsumer; consumer.setId(sourceId); consumer.setId(id); } else { consumer = mConsumerCreator.apply(this, source); consumer = mConsumerCreator.apply(this, id, type); } mSourceConsumers.put(sourceId, consumer); mSourceConsumers.put(id, consumer); return consumer; } Loading @@ -1663,8 +1663,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return mImeSourceConsumer; } @VisibleForTesting public void notifyVisibilityChanged() { void notifyVisibilityChanged() { mHost.notifyInsetsChanged(); } Loading
core/java/android/view/InsetsSourceConsumer.java +6 −3 Original line number Diff line number Diff line Loading @@ -149,9 +149,12 @@ public class InsetsSourceConsumer { // Check if we need to restore server visibility. final InsetsSource localSource = mState.peekSource(mId); final InsetsSource serverSource = mController.getLastDispatchedState().peekSource(mId); if (localSource != null && serverSource != null && localSource.isVisible() != serverSource.isVisible()) { localSource.setVisible(serverSource.isVisible()); final boolean localVisible = localSource != null && localSource.isVisible(); final boolean serverVisible = serverSource != null && serverSource.isVisible(); if (localSource != null) { localSource.setVisible(serverVisible); } if (localVisible != serverVisible) { mController.notifyVisibilityChanged(); } } else { Loading
core/jni/android_view_InputDevice.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,13 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi return NULL; } // b/274058082: Pass a copy of the key character map to avoid concurrent // access std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap(); if (map != nullptr) { map = std::make_shared<KeyCharacterMap>(*map); } ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str())); if (!descriptorObj.get()) { Loading @@ -62,7 +69,7 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi ScopedLocalRef<jobject> kcmObj(env, android_view_KeyCharacterMap_create(env, deviceInfo.getId(), deviceInfo.getKeyCharacterMap())); map)); if (!kcmObj.get()) { return NULL; } Loading