MessageCompat.java
/*
* Copyright 2018 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 androidx.core.os;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link Message}.
*/
public final class MessageCompat {
/**
* False when linking of the hidden setAsynchronous method on pre-22 has previously failed.
* Not volatile because we don't care if multiple threads make an attempt.
*/
private static boolean sTrySetAsynchronous = true;
/**
* False when linking of the hidden isAsynchronous method on pre-22 has previously failed.
* Not volatile because we don't care if multiple threads make an attempt.
*/
private static boolean sTryIsAsynchronous = true;
/**
* Sets whether the message is asynchronous, meaning that it is not
* subject to {@link Looper} synchronization barriers.
* <p>
* Certain operations, such as view invalidation, may introduce synchronization
* barriers into the {@link Looper}'s message queue to prevent subsequent messages
* from being delivered until some condition is met. In the case of view invalidation,
* messages which are posted after a call to {@link View#invalidate}
* are suspended by means of a synchronization barrier until the next frame is
* ready to be drawn. The synchronization barrier ensures that the invalidation
* request is completely handled before resuming.
* <p>
* Asynchronous messages are exempt from synchronization barriers. They typically
* represent interrupts, input events, and other signals that must be handled independently
* even while other work has been suspended.
* <p>
* Note that asynchronous messages may be delivered out of order with respect to
* synchronous messages although they are always delivered in order among themselves.
* If the relative order of these messages matters then they probably should not be
* asynchronous in the first place. Use with caution.
* <p>
* This API has no effect prior to API 16.
*
* @param async True if the message is asynchronous.
*
* @see #isAsynchronous(Message)
* @see Message#setAsynchronous(boolean)
*/
@SuppressLint("NewApi")
public static void setAsynchronous(@NonNull Message message, boolean async) {
if (Build.VERSION.SDK_INT >= 22) {
Api22Impl.setAsynchronous(message, async);
return;
}
if (sTrySetAsynchronous && Build.VERSION.SDK_INT >= 16) {
// Since this was an @hide method made public, we can link directly against it with a
// try/catch for its absence instead of doing the same dance through reflection.
try {
Api22Impl.setAsynchronous(message, async);
} catch (NoSuchMethodError e) {
sTrySetAsynchronous = false;
}
}
}
/**
* Returns true if the message is asynchronous, meaning that it is not
* subject to {@link Looper} synchronization barriers.
*
* @return True if the message is asynchronous. Always false prior to API 16.
*
* @see #setAsynchronous(Message, boolean)
* @see Message#isAsynchronous()
*/
@SuppressLint("NewApi")
public static boolean isAsynchronous(@NonNull Message message) {
if (Build.VERSION.SDK_INT >= 22) {
return Api22Impl.isAsynchronous(message);
}
if (sTryIsAsynchronous && Build.VERSION.SDK_INT >= 16) {
// Since this was an @hide method made public, we can link directly against it with a
// try/catch for its absence instead of doing the same dance through reflection.
try {
return Api22Impl.isAsynchronous(message);
} catch (NoSuchMethodError e) {
sTryIsAsynchronous = false;
}
}
return false;
}
private MessageCompat() {
}
@RequiresApi(22)
static class Api22Impl {
private Api22Impl() {
// This class is not instantiable.
}
@DoNotInline
static boolean isAsynchronous(Message message) {
return message.isAsynchronous();
}
@DoNotInline
static void setAsynchronous(Message message, boolean async) {
message.setAsynchronous(async);
}
}
}