下面列出了怎么用androidx.annotation.MainThread的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Ensure that the HID Device SDP record is registered and start listening for the profile proxy
* and HID Host connection state changes.
*
* @param context Context that is required to listen for battery charge.
* @param listener Callback that will receive the profile events.
* @return Interface for managing the paired HID Host devices.
*/
@MainThread
public HidDeviceProfile register(Context context, ProfileListener listener) {
synchronized (lock) {
if (!listeners.add(listener)) {
// This user is already registered
return hidDeviceProfile;
}
if (listeners.size() > 1) {
// There are already some users
return hidDeviceProfile;
}
context = checkNotNull(context).getApplicationContext();
hidDeviceProfile.registerServiceListener(context, profileListener);
hidDeviceApp.registerDeviceListener(profileListener);
context.registerReceiver(
batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
return hidDeviceProfile;
}
/**
* Initiate connection sequence for the specified HID Host. If another device is already
* connected, it will be disconnected first. If the parameter is {@code null}, then the service
* will only disconnect from the current device.
*
* @param device New HID Host to connect to or {@code null} to disconnect.
*/
@MainThread
public void requestConnect(BluetoothDevice device) {
synchronized (lock) {
waitingForDevice = device;
if (!isAppRegistered) {
// Request will be fulfilled as soon the as app becomes registered.
return;
}
connectedDevice = null;
updateDeviceList();
if (device != null && device.equals(connectedDevice)) {
for (ProfileListener listener : listeners) {
listener.onConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED);
}
}
}
}
@Override
@MainThread
public void onConnectionStateChanged(BluetoothDevice device, int state) {
synchronized (lock) {
if (state == BluetoothProfile.STATE_CONNECTED) {
// A new connection was established. If we weren't expecting that, it
// must be an incoming one. In that case, we shouldn't try to disconnect
// from it.
waitingForDevice = device;
} else if (state == BluetoothProfile.STATE_DISCONNECTED) {
// If we are disconnected from a device we are waiting to connect to, we
// ran into a timeout and should no longer try to connect.
if (device == waitingForDevice) {
waitingForDevice = null;
}
}
updateDeviceList();
for (ProfileListener listener : listeners) {
listener.onConnectionStateChanged(device, state);
}
}
}
@Override
@MainThread
public void onAppStatusChanged(boolean registered) {
synchronized (lock) {
if (isAppRegistered == registered) {
// We are already in the correct state.
return;
}
isAppRegistered = registered;
for (ProfileListener listener : listeners) {
listener.onAppStatusChanged(registered);
}
if (registered && waitingForDevice != null) {
// Fulfill the postponed request to connect.
requestConnect(waitingForDevice);
}
}
}
/**
* If the activity isn't in the specified language, it will restart the activity.
*/
@MainThread
public static void recreateIfNotInCorrectLanguage(Activity activity, String language) {
Locale currentActivityLocale = ConfigurationCompat.getLocales(activity.getResources().getConfiguration()).get(0);
Locale selectedLocale = LocaleParser.findBestMatchingLocaleForLanguage(language);
if (currentActivityLocale.equals(selectedLocale)) {
reentryProtection = "";
return;
}
String reentryKey = activity.getClass().getName() + ":" + selectedLocale;
if (!reentryKey.equals(reentryProtection)) {
reentryProtection = reentryKey;
Log.d(TAG, String.format("Activity Locale %s, Selected locale %s, restarting", currentActivityLocale, selectedLocale));
activity.recreate();
} else {
Log.d(TAG, String.format("Skipping recreate as looks like looping, Activity Locale %s, Selected locale %s", currentActivityLocale, selectedLocale));
}
}
/**
* Starts to listen the given {@code source} LiveData, {@code onChanged} observer will be called
* when {@code source} value was changed.
* <p>
* {@code onChanged} callback will be called only when this {@code MediatorLiveData} is active.
* <p> If the given LiveData is already added as a source but with a different Observer,
* {@link IllegalArgumentException} will be thrown.
*
* @param source the {@code LiveData} to listen to
* @param onChanged The observer that will receive the events
* @param <S> The type of data hold by {@code source} LiveData
*/
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
@MainThread
public void onLock() {
Log.i(TAG, "onLock()");
stopService(new Intent(this, WebRtcCallService.class));
finalizeRevealableMessageManager();
finalizeExpiringMessageManager();
finalizeMessageRetrieval();
unregisterKeyEventReceiver();
Util.runOnMainDelayed(() -> {
ApplicationDependencies.getJobManager().shutdown(TimeUnit.SECONDS.toMillis(10));
KeyCachingService.clearMasterSecret();
WipeMemoryService.run(this, true);
}, TimeUnit.SECONDS.toMillis(1));
}
@MainThread
public static void selectRecipientThroughDialog(@NonNull Context context, @NonNull List<Recipient> choices, @NonNull Locale locale, @NonNull RecipientSelectedCallback callback) {
if (choices.size() > 1) {
CharSequence[] values = new CharSequence[choices.size()];
for (int i = 0; i < values.length; i++) {
values[i] = getPrettyPhoneNumber(choices.get(i).requireE164(), locale);
}
new AlertDialog.Builder(context)
.setItems(values, ((dialog, which) -> callback.onSelected(choices.get(which))))
.create()
.show();
} else {
callback.onSelected(choices.get(0));
}
}
/**
* Stops to listen the given {@code LiveData}.
*
* @param toRemote {@code LiveData} to stop to listen
* @param <S> the type of data hold by {@code source} LiveData
*/
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
Source<?> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
/** Close the profile service connection. */
@MainThread
void unregisterServiceListener() {
if (service != null) {
try {
bluetoothAdapter.closeProfileProxy(BluetoothProfile.HID_DEVICE, service);
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up proxy", t);
}
service = null;
}
serviceStateListener = null;
}
/**
* Initiate the connection to the remote HID Host device.
*
* @param device Device to connect to.
*/
@MainThread
void connect(BluetoothDevice device) {
if (service != null && isProfileSupported(device)) {
service.connect(device);
}
}
/**
* Close the connection with the remote HID Host device.
*
* @param device Device to disconnect from.
*/
@MainThread
void disconnect(BluetoothDevice device) {
if (service != null && isProfileSupported(device)) {
service.disconnect(device);
}
}
/**
* Get all devices that are in the "Connected" state.
*
* @return Connected devices list.
*/
@MainThread
List<BluetoothDevice> getConnectedDevices() {
if (service == null) {
return new ArrayList<>();
}
return service.getConnectedDevices();
}
@MainThread
public long getId(@NonNull E item) {
if (keys.containsKey(item)) {
return keys.get(item);
}
long key = index++;
keys.put(item, key);
return key;
}
@Override
@MainThread
public void onServiceDisconnected(int profile) {
service = null;
if (serviceStateListener != null) {
serviceStateListener.onServiceStateChanged(null);
}
}
/**
* Register the HID Device's SDP record.
*
* @param inputHost Interface for managing the paired HID Host devices and sending the data.
*/
@MainThread
void registerApp(BluetoothProfile inputHost) {
this.inputHost = checkNotNull((BluetoothHidDevice) inputHost);
this.inputHost.registerApp(
Constants.SDP_RECORD, null, Constants.QOS_OUT, Runnable::run, callback);
}
/**
* Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity
* is alive. More detailed explanation is in {@link ViewModel}.
* <p>
* It uses the given {@link Factory} to instantiate new ViewModels.
*
* @param activity an activity, in whose scope ViewModels should be retained
* @param factory a {@code Factory} to instantiate new ViewModels
* @return a ViewModelProvider instance
*/
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
@Override
@MainThread
public void sendBatteryLevel(float level) {
// Store the current values in case the host will try to read them with a GET_REPORT call.
byte[] report = batteryReport.setValue(level);
if (inputHost != null && device != null) {
inputHost.sendReport(device, Constants.ID_BATTERY, report);
}
}
@MainThread
private void onBatteryChanged(Intent intent) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if (level >= 0 && scale > 0) {
float batteryLevel = (float) level / (float) scale;
hidDeviceApp.sendBatteryLevel(batteryLevel);
} else {
Log.e(TAG, "Bad battery level data received: level=" + level + ", scale=" + scale);
}
}
@MainThread
private void onObjectsDetected(FirebaseVisionImage image, List<FirebaseVisionObject> objects) {
detectedObjectNum = objects.size();
Log.d(TAG, "Detected objects num: " + detectedObjectNum);
if (detectedObjectNum == 0) {
loadingView.setVisibility(View.GONE);
showBottomPromptChip(getString(R.string.static_image_prompt_detected_no_results));
} else {
searchedObjectMap.clear();
for (int i = 0; i < objects.size(); i++) {
searchEngine.search(new DetectedObject(objects.get(i), i, image), /* listener= */ this);
}
}
}
@MainThread
public void confirmingObject(DetectedObject object, float progress) {
boolean isConfirmed = (Float.compare(progress, 1f) == 0);
if (isConfirmed) {
confirmedObject = object;
if (PreferenceUtils.isAutoSearchEnabled(getContext())) {
setWorkflowState(WorkflowState.SEARCHING);
triggerSearch(object);
} else {
setWorkflowState(WorkflowState.CONFIRMED);
}
} else {
setWorkflowState(WorkflowState.CONFIRMING);
}
}
/**
* Identical to {@link LayoutInflater#inflate(int, ViewGroup, boolean)}, but will prioritize
* pulling a cached view first.
*/
@MainThread
@SuppressWarnings("unchecked")
public <V extends View> V inflate(@LayoutRes int layoutRes, @Nullable ViewGroup parent, boolean attachToRoot) {
View cached = ViewCache.getInstance().pull(layoutRes);
if (cached != null) {
if (parent != null && attachToRoot) {
parent.addView(cached);
}
return (V) cached;
} else {
return (V) LayoutInflater.from(context).inflate(layoutRes, parent, attachToRoot);
}
}
@Override
@MainThread
public void onAppStatusChanged(boolean registered) {
if (!registered) {
ui.onDeviceDisconnected();
}
}
@Override
@MainThread
public void onAppStatusChanged(boolean registered) {
if (!registered) {
ui.onDeviceDisconnected();
}
}
@MainThread
@Override
public void run() {
boolean isActive = mLiveData.hasActiveObservers();
if (mInvalid.compareAndSet(false, true)) {
if (isActive) {
mExecutor.execute(mRefreshRunnable);
}
}
}
@Override
@MainThread
public void onAppStatusChanged(boolean registered) {
if (!registered) {
ui.onDeviceDisconnected();
}
}
@Override
@MainThread
public void onAppStatusChanged(boolean registered) {
if (!registered) {
ui.onDeviceDisconnected();
}
}
@MainThread
MeteredConnectivityObserver(@NonNull Context context, @NonNull LifecycleOwner lifecycleOwner) {
this.context = context;
this.connectivityManager = ServiceUtil.getConnectivityManager(context);
this.metered = new MutableLiveData<>();
this.metered.setValue(ConnectivityManagerCompat.isActiveNetworkMetered(connectivityManager));
lifecycleOwner.getLifecycle().addObserver(this);
}
/**
* Provided a pool, this will initialize it with view counts that make sense.
*/
@MainThread
static void initializePool(@NonNull RecyclerView.RecycledViewPool pool) {
pool.setMaxRecycledViews(MESSAGE_TYPE_INCOMING_TEXT, 15);
pool.setMaxRecycledViews(MESSAGE_TYPE_INCOMING_MULTIMEDIA, 15);
pool.setMaxRecycledViews(MESSAGE_TYPE_OUTGOING_TEXT, 15);
pool.setMaxRecycledViews(MESSAGE_TYPE_OUTGOING_MULTIMEDIA, 15);
pool.setMaxRecycledViews(MESSAGE_TYPE_PLACEHOLDER, 15);
pool.setMaxRecycledViews(MESSAGE_TYPE_HEADER, 1);
pool.setMaxRecycledViews(MESSAGE_TYPE_FOOTER, 1);
pool.setMaxRecycledViews(MESSAGE_TYPE_UPDATE, 5);
}
@MainThread
private void cleanFastRecords() {
Util.assertMainThread();
synchronized (releasedFastRecords) {
Iterator<MessageRecord> recordIterator = fastRecords.iterator();
while (recordIterator.hasNext()) {
long id = recordIterator.next().getId();
if (releasedFastRecords.contains(id)) {
recordIterator.remove();
releasedFastRecords.remove(id);
}
}
}
}