Here are the examples of the java api android.os.Looper taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
311 Examples
19
Source : IjkMediaPlayer.java
with MIT License
from zzh12138
with MIT License
from zzh12138
private void initPlayer(IjkLibLoader libLoader, Context context) {
loadLibrariesOnce(libLoader, context);
initNativeOnce();
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
/*
* Native setup requires a weak reference to our object. It's easier to
* create it here than in C++.
*/
native_setup(new WeakReference<IjkMediaPlayer>(this));
}
19
Source : VideoPlayer.java
with MIT License
from Zhaoss
with MIT License
from Zhaoss
private void initPlayer() {
initNativeOnce();
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
native_setup(new WeakReference<VideoPlayer>(this));
}
19
Source : LoaderService.java
with MIT License
from zerobranch
with MIT License
from zerobranch
public clreplaced LoaderService extends Service {
private volatile Looper serviceLooper;
private volatile Handler handler;
public static final int DEFAULT_NOTIFICATION_ID = 43534;
private ArrayList<String> urls;
@Override
public void onCreate() {
super.onCreate();
final HandlerThread thread = new HandlerThread(LoaderService.clreplaced.getName());
thread.start();
serviceLooper = thread.getLooper();
handler = new Handler(serviceLooper, handlerCallback);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
urls = intent.getStringArrayListExtra(BundleConst.URL);
for (int i = 0; i < urls.size(); i++) {
final Message msg = handler.obtainMessage();
msg.arg1 = startId;
msg.arg2 = i;
msg.obj = intent;
handler.sendMessage(msg);
}
return START_NOT_STICKY;
}
@SuppressWarnings("deprecation")
private void setImmortal(Intent intent) {
final boolean isHideNotification = intent.getBooleanExtra(BundleConst.DEFAULT_NOTIFICATION, false);
final boolean isImmortal = intent.getBooleanExtra(BundleConst.IMMORTAL, false);
final Notification notification = intent.getParcelableExtra(BundleConst.NOTIFICATION);
if (isImmortal) {
if (notification != null) {
startForeground(DEFAULT_NOTIFICATION_ID, notification);
} else {
startForeground(DEFAULT_NOTIFICATION_ID, new Notification.Builder(this).build());
if (isHideNotification) {
startService(new Intent(this, HideNotificationService.clreplaced));
}
}
}
}
@Override
public void onDestroy() {
serviceLooper.quit();
serviceLooper.getThread().interrupt();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private final Handler.Callback handlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
final Intent intent = (Intent) msg.obj;
final int urlIndex = msg.arg2;
setImmortal(intent);
onHandleIntent(intent, urls.get(urlIndex));
stopForeground(intent.getBooleanExtra(BundleConst.VIEW_NOTIFICATION_ON_FINISH, false));
if (urlIndex == urls.size() - 1) {
stopSelf(msg.arg1);
}
return true;
}
};
private void onHandleIntent(Intent intent, String url) {
final String path = intent.getStringExtra(BundleConst.PATH);
final ResultReceiver receiver = intent.getParcelableExtra(BundleConst.RECEIVER);
new LoadManager().skipIfFileExist(intent.getBooleanExtra(BundleConst.SKIP_IF_EXIST, false)).abortNextIfError(intent.getBooleanExtra(BundleConst.ABORT_IF_ERROR, false)).redownloadAttemptCount(intent.getIntExtra(BundleConst.REDOWNLOAD_COUNT, 0)).loadFile(path, url, receiver);
}
}
19
Source : Daemon.java
with Apache License 2.0
from YuntaoWei
with Apache License 2.0
from YuntaoWei
/**
* 常驻的后台线程,用于处理一个消息循环
* <p/>
* 一般用于处理运算密集型任务、磁盘IO任务等执行时间小于1秒的任务
*/
public clreplaced Daemon {
private static volatile boolean shouldStop;
private static Thread thread = null;
private static Looper looper = null;
public static synchronized void start() {
if (thread == null) {
final BlockingItem<Looper> bl = new BlockingItem<Looper>();
thread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Looper l = Looper.myLooper();
bl.put(l);
while (!shouldStop) {
try {
Looper.loop();
} catch (Exception e) {
}
}
}
}, "daemon");
shouldStop = false;
thread.start();
try {
looper = bl.take();
} catch (InterruptedException e) {
}
}
}
public static synchronized void stop() {
shouldStop = true;
if (thread != null && looper != null) {
looper.quit();
try {
thread.join();
} catch (Exception e) {
}
thread = null;
looper = null;
}
}
public static Looper looper() {
if (looper == null) {
start();
}
return looper == null ? Looper.getMainLooper() : looper;
}
}
19
Source : PermissionsResultAction.java
with Apache License 2.0
from ykbjson
with Apache License 2.0
from ykbjson
/**
* Desription:<p>This abstract clreplaced should be used to create an if/else action that the PermissionsManager
* can execute when the permissions you request are granted or denied. Simple use involves
* creating an anonymous instance of it and preplaceding that instance to the
* requestPermissionsIfNecessaryForResult method. The result will be sent back to you as
* either onGranted (all permissions have been granted), or onDenied (a required permission
* has been denied). Ideally you put your functionality in the onGranted method and notify
* the user what won't work in the onDenied method.</p>
* Creator:yankebin
* CreatedAt:2018/11/7
*/
public clreplaced PermissionsResultAction {
private final String TAG = getClreplaced().getName();
private Looper mLooper = Looper.getMainLooper();
private final Set<String> mPermissions = new HashSet<>(1);
private final Set<String> mDeniedPermissions = new HashSet<>(1);
private final PermissionsRequestCallback mPermissionsRequestCallback;
private final int mRequestCode;
/**
* Default Constructor
*/
public PermissionsResultAction(int requestCode, @Nullable PermissionsRequestCallback permissionsRequestCallback) {
mRequestCode = requestCode;
mPermissionsRequestCallback = permissionsRequestCallback;
}
/**
* Alternate Constructor. Preplaced the looper you wish the PermissionsResultAction
* callbacks to be executed on if it is not the current Looper. For instance,
* if you are making a permissions request from a background thread but wish the
* callback to be on the UI thread, use this constructor to specify the UI Looper.
*
* @param looper the looper that the callbacks will be called using.
*/
public PermissionsResultAction(int requestCode, @Nullable PermissionsRequestCallback permissionsRequestCallback, @NonNull Looper looper) {
this(requestCode, permissionsRequestCallback);
mLooper = looper;
}
/**
* This method is called when a permission that have been
* requested have been granted by the user. In this method
* you should put your permission(s) sensitive code that can
* only be executed with the required permissions.
*/
public void onGranted(String permission) {
if (null != mPermissionsRequestCallback) {
mPermissionsRequestCallback.onGranted(mRequestCode, permission);
}
}
/**
* This method is called when a permission has been denied by
* the user. It provides you with the permission that was denied
* and will be executed on the Looper you preplaced to the constructor
* of this clreplaced, or the Looper that this object was created on.
*
* @param permission the permission that was denied.
*/
public void onDenied(String permission) {
if (null != mPermissionsRequestCallback) {
mPermissionsRequestCallback.onDenied(mRequestCode, permission);
}
}
/**
* This method is called when a permission has been denied by
* the user forever. It provides you with the permission that was denied
* and will be executed on the Looper you preplaced to the constructor
* of this clreplaced, or the Looper that this object was created on.
*
* @param permission the permission that was denied.
*/
public void onDeniedForever(String permission) {
if (null != mPermissionsRequestCallback) {
mPermissionsRequestCallback.onDeniedForever(mRequestCode, permission);
}
}
/**
* This method is called when all permissions has been check complete
* but some permissions denied.
*
* @param deniedPermissions those denied permissions
*/
public void onFailure(String[] deniedPermissions) {
if (null != mPermissionsRequestCallback) {
mPermissionsRequestCallback.onFailure(mRequestCode, deniedPermissions);
}
}
/**
* This method is called when all permissions has been check complete
* and all permissions granted.
*/
public void onSuccess() {
if (null != mPermissionsRequestCallback) {
mPermissionsRequestCallback.onSuccess(mRequestCode);
}
}
/**
* This method is used to determine if a permission not
* being present on the current Android platform should
* affect whether the PermissionsResultAction should continue
* listening for events. By default, it returns true and will
* simply ignore the permission that did not exist. Usually this will
* work fine since most new permissions are introduced to
* restrict what was previously allowed without permission.
* If that is not the case for your particular permission you
* request, override this method and return false to result in the
* Action being denied.
*
* @param permission the permission that doesn't exist on this
* Android version
* @return return true if the PermissionsResultAction should
* ignore the lack of the permission and proceed with exection
* or false if the PermissionsResultAction should treat the
* absence of the permission on the API level as a denial.
*/
public synchronized boolean shouldIgnorePermissionNotFound(String permission) {
if (PermissionsManager.getInstance().isEnableLog()) {
Log.d(TAG, "Permission not found: " + permission);
}
return true;
}
@CallSuper
protected synchronized final boolean onResult(@NonNull final String permission, int result) {
if (result == PackageManager.PERMISSION_GRANTED) {
return onResult(permission, Permissions.GRANTED);
} else {
return onResult(permission, Permissions.DENIED);
}
}
/**
* This method is called when a particular permission has changed.
* This method will be called for all permissions, so this method determines
* if the permission affects the state or not and whether it can proceed with
* calling onGranted or if onDenied should be called.
*
* @param permission the permission that changed.
* @param result the result for that permission.
* @return this method returns true if its primary action has been completed
* and it should be removed from the data structure holding a reference to it.
*/
@CallSuper
protected synchronized final boolean onResult(@NonNull final String permission, Permissions result) {
mPermissions.remove(permission);
boolean onResult = false;
if (result == Permissions.GRANTED) {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
PermissionsResultAction.this.onGranted(permission);
}
});
} else if (result == Permissions.DENIED) {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
PermissionsResultAction.this.onDenied(permission);
}
});
} else if (result == Permissions.NOT_FOUND) {
if (shouldIgnorePermissionNotFound(permission)) {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
PermissionsResultAction.this.onGranted(permission);
}
});
} else {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
PermissionsResultAction.this.onDenied(permission);
}
});
}
} else if (result == Permissions.USER_DENIED_FOREVER) {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
PermissionsResultAction.this.onDeniedForever(permission);
}
});
}
// 标记不被通过的权限
if (result == Permissions.DENIED || (result == Permissions.NOT_FOUND && !shouldIgnorePermissionNotFound(permission))) {
mDeniedPermissions.add(permission);
}
if (mPermissions.isEmpty()) {
getSchedule().scheduleDirect(new Runnable() {
@Override
public void run() {
if (mDeniedPermissions.isEmpty()) {
PermissionsResultAction.this.onSuccess();
} else {
final String[] deniedPermissions = (String[]) mDeniedPermissions.toArray(new String[mDeniedPermissions.size()]);
PermissionsResultAction.this.onFailure(deniedPermissions);
}
// 重置不被通过的权限存储
mDeniedPermissions.clear();
}
});
onResult = true;
}
return onResult;
}
/**
* This method registers the PermissionsResultAction object for the specified permissions
* so that it will know which permissions to look for changes to. The PermissionsResultAction
* will then know to look out for changes to these permissions.
*
* @param perms the permissions to listen for
*/
@SuppressWarnings("WeakerAccess")
@CallSuper
protected synchronized final void registerPermissions(@NonNull String[] perms) {
Collections.addAll(mPermissions, perms);
}
/**
* 获取执行权限回调的线程调度器
*
* @return
*/
protected synchronized Scheduler getSchedule() {
return null == mLooper ? AndroidSchedulers.mainThread() : AndroidSchedulers.from(mLooper);
}
protected int getRequestCode() {
return mRequestCode;
}
}
19
Source : Player.java
with MIT License
from xinpianchang
with MIT License
from xinpianchang
/**
* 使用播放器模块 需要主动调用该类init方法
*/
public clreplaced Player {
private static Looper mStateMachineLooper;
public static void init(@NonNull Context context) {
init(context, null);
}
public static void init(@NonNull Context context, @Nullable Looper looper) {
ConnectionUtils.init(context);
// 初始化播放器所需要的Looper.
if (looper == null) {
HandlerThread handlerThread = new HandlerThread("player");
handlerThread.start();
mStateMachineLooper = handlerThread.getLooper();
} else {
mStateMachineLooper = looper;
}
}
@NonNull
public static Looper getStateMachineLooper() {
if (mStateMachineLooper == null) {
throw new IllegalArgumentException("You must init first.");
}
return mStateMachineLooper;
}
}
19
Source : IjkMediaPlayer.java
with GNU General Public License v3.0
from xdtianyu
with GNU General Public License v3.0
from xdtianyu
private void initPlayer(IjkLibLoader libLoader) {
loadLibrariesOnce(libLoader);
initNativeOnce();
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
/*
* Native setup requires a weak reference to our object. It's easier to
* create it here than in C++.
*/
native_setup(new WeakReference<IjkMediaPlayer>(this));
}
19
Source : FimiMediaPlayer.java
with MIT License
from wladimir-computin
with MIT License
from wladimir-computin
private void initPlayer(FimiLibLoader libLoader) {
loadLibrariesOnce(libLoader);
initNativeOnce();
Looper looper = Looper.myLooper();
if (looper != null) {
this.mEventHandler = new EventHandler(this, looper);
} else {
looper = Looper.getMainLooper();
if (looper != null) {
this.mEventHandler = new EventHandler(this, looper);
} else {
this.mEventHandler = null;
}
}
native_setup(new WeakReference(this));
}
19
Source : SystemClock.java
with GNU General Public License v2.0
from warren-bank
with GNU General Public License v2.0
from warren-bank
@Override
public HandlerWrapper createHandler(Looper looper, @Nullable Callback callback) {
return new SystemHandlerWrapper(new Handler(looper, callback));
}
19
Source : Loader.java
with GNU General Public License v2.0
from warren-bank
with GNU General Public License v2.0
from warren-bank
/**
* Starts loading a {@link Loadable}.
*
* <p>The calling thread must be a {@link Looper} thread, which is the thread on which the {@link
* Callback} will be called.
*
* @param <T> The type of the loadable.
* @param loadable The {@link Loadable} to load.
* @param callback A callback to be called when the load ends.
* @param looper The {@link Looper} thread.
* @param defaultMinRetryCount The minimum number of times the load must be retried before {@link
* #maybeThrowError()} will propagate an error.
* @throws IllegalStateException If the calling thread does not have an replacedociated {@link Looper}.
* @return {@link SystemClock#elapsedRealtime} when the load started.
*/
public <T extends Loadable> long startLoading(T loadable, Callback<T> callback, Looper looper, int defaultMinRetryCount) {
replacedertions.checkState(looper != null);
fatalError = null;
long startTimeMs = SystemClock.elapsedRealtime();
new LoadTask<>(looper, loadable, callback, defaultMinRetryCount, startTimeMs).start(0);
return startTimeMs;
}
19
Source : DefaultDrmSessionManager.java
with GNU General Public License v2.0
from warren-bank
with GNU General Public License v2.0
from warren-bank
@Override
public DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData) {
replacedertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper);
if (sessions.isEmpty()) {
this.playbackLooper = playbackLooper;
if (mediaDrmHandler == null) {
mediaDrmHandler = new MediaDrmHandler(playbackLooper);
}
}
List<SchemeData> schemeDatas = null;
if (offlineLicenseKeySetId == null) {
schemeDatas = getSchemeDatas(drmInitData, uuid, false);
if (schemeDatas.isEmpty()) {
final MissingSchemeDataException error = new MissingSchemeDataException(uuid);
eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(error));
return new ErrorStateDrmSession<>(new DrmSessionException(error));
}
}
DefaultDrmSession<T> session;
if (!multiSession) {
session = sessions.isEmpty() ? null : sessions.get(0);
} else {
// Only use an existing session if it has matching init data.
session = null;
for (DefaultDrmSession<T> existingSession : sessions) {
if (Util.areEqual(existingSession.schemeDatas, schemeDatas)) {
session = existingSession;
break;
}
}
}
if (session == null) {
// Create a new session.
session = new DefaultDrmSession<>(uuid, mediaDrm, this, schemeDatas, mode, offlineLicenseKeySetId, optionalKeyRequestParameters, callback, playbackLooper, eventDispatcher, initialDrmRequestRetryCount);
sessions.add(session);
}
session.acquire();
return session;
}
19
Source : HTTPTask.java
with Apache License 2.0
from vimfung
with Apache License 2.0
from vimfung
/**
* 上传文件
*
* @param fileParams 文件参数
* @param parameters 请求参数
* @param resultHandler 返回回调
* @param faultHandler 失败回调
* @param progressHandler 上传进度回调
*/
public void upload(final HashMap<String, HTTPFile> fileParams, final HashMap<String, String> parameters, final LuaFunction resultHandler, final LuaFunction faultHandler, final LuaFunction progressHandler) {
if (url == null) {
return;
}
// 取消之前的请求
cancel();
Looper mainLooper = Looper.getMainLooper();
final Handler mainHandler = new Handler(mainLooper);
new Thread(new Runnable() {
@Override
public void run() {
try {
// 总上传字节
long totalUploadedBytes = 0;
long uploadedBytes = 0;
URL requestURL = new URL(url);
_curConn = (HttpURLConnection) requestURL.openConnection();
try {
_curConn.setRequestMethod("POST");
_curConn.setConnectTimeout(timeout * 1000);
// 分块传输
_curConn.setChunkedStreamingMode(4096);
fillHttpHeaders();
// 生成Boundary String
int boundaryStringId = new Random().nextInt(9999999 - 123400) + 123400;
String boundaryString = String.format(Locale.getDefault(), "Boundary-%d", boundaryStringId);
String contentType = String.format(Locale.getDefault(), "multipart/form-data; boundary=%s", boundaryString);
_curConn.addRequestProperty("Content-Type", contentType);
_curConn.setDoOutput(true);
_curConn.setDoInput(true);
// POST请求不能用缓存,设置为false
_curConn.setUseCaches(false);
// 连接服务器
_curConn.connect();
// 得到httpURLConnection的输出流
OutputStream os = _curConn.getOutputStream();
try {
os.write(String.format(Locale.getDefault(), "--%s\r\n", boundaryString).getBytes());
String endItemBoundaryString = String.format(Locale.getDefault(), "\r\n--%s\r\n", boundaryString);
// 填充上传文件数据
if (fileParams != null) {
// 计算总的文件大小
totalUploadedBytes = getUploadFilesLength(fileParams);
// 写入文件数据
sendUploadFilesData(fileParams, os, boundaryString, totalUploadedBytes, progressHandler);
}
// 写入请求参数
if (parameters != null) {
int paramIndex = 0;
for (Map.Entry<String, String> entry : parameters.entrySet()) {
String contentDisposition = String.format(Locale.getDefault(), "Content-Disposition: form-data; name=\"%s\"\r\n\r\n", Encoding.urlEncode(entry.getKey()));
os.write(contentDisposition.getBytes());
os.write(Encoding.urlEncode(entry.getValue()).getBytes());
if (paramIndex < parameters.size() - 1) {
os.write(endItemBoundaryString.getBytes());
}
paramIndex++;
}
}
os.write(String.format(Locale.getDefault(), "\r\n--%s--\r\n", boundaryString).getBytes());
// 刷新对象输出流,将字节全部写入输出流中
os.flush();
} finally {
// 关闭流对象
os.close();
}
dealResponse(null, resultHandler, faultHandler, null);
} finally {
_curConn.disconnect();
}
} catch (final MalformedURLException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
} catch (final IOException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
}
}
}).start();
}
19
Source : HTTPTask.java
with Apache License 2.0
from vimfung
with Apache License 2.0
from vimfung
/**
* 发起POST请求
*
* @param parameters 请求参数
* @param resultHandler 返回回调
* @param faultHandler 失败回调
*/
public void post(final Map<String, String> parameters, final LuaFunction resultHandler, final LuaFunction faultHandler) {
if (url == null) {
return;
}
// 取消之前的请求
cancel();
Looper mainLooper = Looper.getMainLooper();
final Handler mainHandler = new Handler(mainLooper);
new Thread(new Runnable() {
@Override
public void run() {
try {
URL requestURL = new URL(url);
_curConn = (HttpURLConnection) requestURL.openConnection();
try {
_curConn.setRequestMethod("POST");
_curConn.setConnectTimeout(timeout * 1000);
fillHttpHeaders();
_curConn.setDoOutput(true);
_curConn.setDoInput(true);
// POST请求不能用缓存,设置为false
_curConn.setUseCaches(false);
// 连接服务器
_curConn.connect();
// 得到httpURLConnection的输出流
OutputStream os = _curConn.getOutputStream();
try {
// 向对象输出流写出数据,这些数据将存到内存缓冲区中
os.write(getParametersString(parameters).getBytes());
// 刷新对象输出流,将字节全部写入输出流中
os.flush();
} finally {
// 关闭流对象
os.close();
}
dealResponse(null, resultHandler, faultHandler, null);
} finally {
_curConn.disconnect();
}
} catch (final MalformedURLException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
} catch (final IOException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
}
}
}).start();
}
19
Source : HTTPTask.java
with Apache License 2.0
from vimfung
with Apache License 2.0
from vimfung
/**
* 下载文件
*
* @param filePath 保存文件的路径
* @param resultHandler 返回回调
* @param faultHandler 失败回调
* @param progressHandler 下载进度回调
*/
public void download(final String filePath, final LuaFunction resultHandler, final LuaFunction faultHandler, final LuaFunction progressHandler) {
if (url == null) {
return;
}
// 取消之前的请求
cancel();
Looper mainLooper = Looper.getMainLooper();
final Handler mainHandler = new Handler(mainLooper);
new Thread(new Runnable() {
@Override
public void run() {
try {
URL requestURL = new URL(url);
_curConn = (HttpURLConnection) requestURL.openConnection();
try {
_curConn.setRequestMethod("GET");
_curConn.setConnectTimeout(timeout * 1000);
fillHttpHeaders();
_curConn.connect();
dealResponse(filePath, resultHandler, faultHandler, progressHandler);
} finally {
_curConn.disconnect();
}
} catch (final MalformedURLException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
} catch (final IOException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
}
}
}).start();
}
19
Source : HTTPTask.java
with Apache License 2.0
from vimfung
with Apache License 2.0
from vimfung
/**
* 发起GET请求
*
* @param resultHandler 返回回调
* @param faultHandler 失败回调
*/
public void get(final LuaFunction resultHandler, final LuaFunction faultHandler) {
if (url == null) {
return;
}
// 先取消之前请求
cancel();
Looper mainLooper = Looper.getMainLooper();
final Handler mainHandler = new Handler(mainLooper);
new Thread(new Runnable() {
@Override
public void run() {
try {
URL requestURL = new URL(url);
_curConn = (HttpURLConnection) requestURL.openConnection();
try {
_curConn.setRequestMethod("GET");
_curConn.setConnectTimeout(timeout * 1000);
fillHttpHeaders();
_curConn.connect();
dealResponse(null, resultHandler, faultHandler, null);
} finally {
_curConn.disconnect();
}
} catch (final MalformedURLException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
} catch (final IOException e) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (faultHandler != null) {
faultHandler.invoke(new LuaValue[] { new LuaValue(e.getMessage()) });
}
}
});
}
}
}).start();
}
19
Source : LooperActorThread.java
with Apache License 2.0
from truecaller
with Apache License 2.0
from truecaller
/* package */
clreplaced LooperActorThread implements ActorThread {
@NonNull
private final FailureHandler mFailureHandler;
@NonNull
private final ProxyFactory mProxyFactory;
@NonNull
private final Looper mLooper;
/* package */
LooperActorThread(@NonNull ProxyFactory proxyFactory, @NonNull FailureHandler failureHandler, @NonNull Looper looper) {
mProxyFactory = proxyFactory;
mFailureHandler = failureHandler;
mLooper = looper;
}
@NonNull
@Override
public <T> ActorRef<T> bind(@NonNull Clreplaced<T> cls, @NonNull T impl) {
MessageSender postman = new LooperMessageSender<>(mLooper, mFailureHandler, impl);
T instance = mProxyFactory.newProxy(cls, postman);
return new ActorRefImpl<>(instance);
}
private static clreplaced LooperMessageSender<T> extends Handler implements MessageSender {
@NonNull
private final FailureHandler mFailureHandler;
@NonNull
private final T mImpl;
/* package */
LooperMessageSender(@NonNull Looper looper, @NonNull FailureHandler failureHandler, @NonNull T impl) {
super(looper);
mFailureHandler = failureHandler;
mImpl = impl;
}
@Override
public void deliver(@NonNull Message message) {
android.os.Message msg = obtainMessage(0, message);
msg.sendToTarget();
}
@SuppressWarnings("unchecked")
@Override
public void handleMessage(@NonNull android.os.Message msg) {
Message<T, ?> message = (Message<T, ?>) msg.obj;
try {
message.invoke(mImpl);
} catch (Throwable e) {
ActorInvokeException call = message.exception();
call.initCause(e);
mFailureHandler.onUncaughtException(mImpl, message, call);
}
}
}
}
19
Source : DefaultActorThread.java
with Apache License 2.0
from truecaller
with Apache License 2.0
from truecaller
private void stopThread(@NonNull Looper looper) {
ActorHandlerBase handler = mHandler;
synchronized (this) {
if (handler == mHandler) {
mHandler = null;
}
}
looper.quit();
}
19
Source : ActorsThreadsBase.java
with Apache License 2.0
from truecaller
with Apache License 2.0
from truecaller
@Override
@NonNull
public ActorThread createThread(@NonNull Looper looper) {
return new LooperActorThread(mProxyFactory, mFailureHandler, looper);
}
19
Source : TDQuitSafelyService.java
with Apache License 2.0
from ThinkingDataAnalytics
with Apache License 2.0
from ThinkingDataAnalytics
private void quitSafely(String threadName, long timeout) {
try {
for (Thread t : Thread.getAllStackTraces().keySet()) {
if (t.getName().equals(threadName)) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (t instanceof HandlerThread) {
Looper l = ((HandlerThread) t).getLooper();
if (null != l) {
l.quitSafely();
if (timeout > 0) {
t.join(timeout);
} else {
t.join(500);
}
}
}
} else {
// Just wait for sending exception data
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
19
Source : LooperWorkRunner.java
with Apache License 2.0
from spotify
with Apache License 2.0
from spotify
/**
* Creates a {@link WorkRunner} backed by the provided {@link Looper}
*
* @param looper the looper to use for processing work
* @return a {@link WorkRunner} that uses the provided {@link Looper} for processing work
*/
public static LooperWorkRunner using(Looper looper) {
return new LooperWorkRunner(looper);
}
19
Source : LooperCompatUtils.java
with Apache License 2.0
from sergchil
with Apache License 2.0
from sergchil
public static void quitSafely(final Looper looper) {
if (null != METHOD_quitSafely) {
CompatUtils.invoke(looper, null, /* default return value */
METHOD_quitSafely);
} else {
looper.quit();
}
}
19
Source : ByteBufferReader.java
with MIT License
from samigehi
with MIT License
from samigehi
private static PriorityQueue<ByteBuffer> getReclaimed() {
Looper mainLooper = Looper.getMainLooper();
if (mainLooper != null) {
if (Thread.currentThread() == mainLooper.getThread())
return null;
}
return reclaimed;
}
19
Source : HandlerThreadHandler.java
with Apache License 2.0
from saki4510t
with Apache License 2.0
from saki4510t
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void quitSafely() throws IllegalStateException {
final Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
} else {
throw new IllegalStateException("has no looper");
}
}
19
Source : HandlerThreadHandler.java
with Apache License 2.0
from saki4510t
with Apache License 2.0
from saki4510t
public boolean isCurrentThread() throws IllegalStateException {
final Looper looper = getLooper();
if (looper != null) {
return mId == Thread.currentThread().getId();
} else {
throw new IllegalStateException("has no looper");
}
}
19
Source : HandlerThreadHandler.java
with Apache License 2.0
from saki4510t
with Apache License 2.0
from saki4510t
public void quit() throws IllegalStateException {
final Looper looper = getLooper();
if (looper != null) {
looper.quit();
} else {
throw new IllegalStateException("has no looper");
}
}
19
Source : ThreadUtils.java
with BSD 3-Clause "New" or "Revised" License
from ridi
with BSD 3-Clause "New" or "Revised" License
from ridi
public static void setUiThread(Looper looper) {
synchronized (sLock) {
if (looper == null) {
// Used to reset the looper after tests.
sUiThreadHandler = null;
return;
}
if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
throw new RuntimeException("UI thread looper is already set to " + sUiThreadHandler.getLooper() + " (Main thread looper is " + Looper.getMainLooper() + "), cannot set to new looper " + looper);
} else {
sUiThreadHandler = new Handler(looper);
}
}
TraceEvent.onUiThreadReady();
}
19
Source : Main.java
with Apache License 2.0
from rayworks
with Apache License 2.0
from rayworks
/**
* Created by seanzhou on 3/14/17.
*/
public clreplaced Main {
private static final String sTAG = Main.clreplaced.getName();
private static final String IMAGE_JPEG = "image/jpeg";
private static final String IMAGE_WEBP = "image/webp";
private static final String IMAGE_PNG = "image/png";
private static final String WIDTH = "width";
private static final String HEIGHT = "height";
private static final String FORMAT = "format";
private static final int SCREENSHOT_DELAY_MILLIS = 1500;
private static Looper looper;
private static int width = 0;
private static int height = 0;
private static int port = 53516;
private static DisplayUtil displayUtil;
private static Handler handler;
public static void main(String[] args) {
resolveArgs(args);
AsyncHttpServer httpServer = new AsyncHttpServer() {
@Override
protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
return super.onRequest(request, response);
}
};
Looper.prepare();
looper = Looper.myLooper();
System.out.println(">>> DroidCast main entry");
handler = new Handler(looper);
displayUtil = new DisplayUtil();
AsyncServer server = new AsyncServer();
httpServer.get("/screenshot", new AnyRequestCallback());
httpServer.websocket("/src", (webSocket, request) -> {
Pair<Integer, Integer> pair = getDimension();
displayUtil.setRotateListener(rotate -> {
System.out.println(">>> rotate to " + rotate);
// delay for the new rotated screen
handler.postDelayed(() -> {
Pair<Integer, Integer> dimen = getDimension();
sendScreenshotData(webSocket, dimen.first, dimen.second);
}, SCREENSHOT_DELAY_MILLIS);
});
sendScreenshotData(webSocket, pair.first, pair.second);
});
httpServer.listen(server, port);
Looper.loop();
}
private static void resolveArgs(String[] args) {
if (args.length > 0) {
String[] params = args[0].split("=");
if ("--port".equals(params[0])) {
try {
port = Integer.parseInt(params[1]);
System.out.println(sTAG + " | Port set to " + port);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
}
@NonNull
private static Pair<Integer, Integer> getDimension() {
Point displaySize = displayUtil.getCurrentDisplaySize();
int width = 1080;
int height = 1920;
if (displaySize != null) {
width = displaySize.x;
height = displaySize.y;
}
return new Pair<>(width, height);
}
private static void sendScreenshotData(WebSocket webSocket, int width, int height) {
try {
byte[] inBytes = getScreenImageInBytes(Bitmap.CompressFormat.JPEG, width, height, (w, h, rotation) -> {
JSONObject obj = new JSONObject();
try {
obj.put("width", w);
obj.put("height", h);
obj.put("rotation", rotation);
webSocket.send(obj.toString());
} catch (JSONException e) {
e.printStackTrace();
}
});
webSocket.send(inBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
private static byte[] getScreenImageInBytes(Bitmap.CompressFormat compressFormat, int w, int h, @Nullable ImageDimensionListener resolver) throws IOException {
int destWidth = w;
int destHeight = h;
Bitmap bitmap = ScreenCaptorUtils.screenshot(destWidth, destHeight);
if (bitmap == null) {
System.out.println(String.format(Locale.ENGLISH, ">>> failed to generate image with resolution %d:%d", Main.width, Main.height));
destWidth /= 2;
destHeight /= 2;
bitmap = ScreenCaptorUtils.screenshot(destWidth, destHeight);
}
System.out.println(String.format(Locale.ENGLISH, "Bitmap generated with resolution %d:%d, process id %d | thread id %d", destWidth, destHeight, Process.myPid(), Process.myTid()));
int screenRotation = displayUtil.getScreenRotation();
if (screenRotation != 0) {
switch(screenRotation) {
case // 90 degree rotation (counter-clockwise)
1:
bitmap = displayUtil.rotateBitmap(bitmap, -90f);
break;
case // 270 degree rotation
3:
bitmap = displayUtil.rotateBitmap(bitmap, 90f);
break;
case // 180 degree rotation
2:
bitmap = displayUtil.rotateBitmap(bitmap, 180f);
break;
default:
break;
}
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
System.out.println("Bitmap final dimens : " + width + "|" + height);
if (resolver != null) {
resolver.onResolveDimension(width, height, screenRotation);
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
bitmap.compress(compressFormat, 100, bout);
bout.flush();
// "Make sure to call Bitmap.recycle() as soon as possible, once its content is not
// needed anymore."
bitmap.recycle();
return bout.toByteArray();
}
interface ImageDimensionListener {
void onResolveDimension(int width, int height, int rotation);
}
static clreplaced AnyRequestCallback implements HttpServerRequestCallback {
private Pair<Bitmap.CompressFormat, String> mapRequestFormatInfo(ImageFormat imageFormat) {
Bitmap.CompressFormat compressFormat;
String contentType;
switch(imageFormat) {
case JPEG:
compressFormat = Bitmap.CompressFormat.JPEG;
contentType = IMAGE_JPEG;
break;
case PNG:
compressFormat = Bitmap.CompressFormat.PNG;
contentType = IMAGE_PNG;
break;
case WEBP:
compressFormat = Bitmap.CompressFormat.WEBP;
contentType = IMAGE_WEBP;
break;
default:
throw new UnsupportedOperationException("Unsupported image format detected");
}
return new Pair<>(compressFormat, contentType);
}
@Nullable
private Pair<Bitmap.CompressFormat, String> getImageFormatInfo(String reqFormat) {
ImageFormat format = ImageFormat.JPEG;
if (!TextUtils.isEmpty(reqFormat)) {
ImageFormat imageFormat = ImageFormat.resolveFormat(reqFormat);
if (ImageFormat.UNKNOWN.equals(imageFormat)) {
return null;
} else {
// default format
format = imageFormat;
}
}
return mapRequestFormatInfo(format);
}
@Override
public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
try {
Multimap pairs = request.getQuery();
String width = pairs.getString(WIDTH);
String height = pairs.getString(HEIGHT);
String reqFormat = pairs.getString(FORMAT);
Pair<Bitmap.CompressFormat, String> formatInfo = getImageFormatInfo(reqFormat);
if (formatInfo == null) {
response.code(400);
response.send(String.format(Locale.ENGLISH, "Unsupported image format : %s", reqFormat));
return;
}
if (!TextUtils.isEmpty(width) && !TextUtils.isEmpty(height) && TextUtils.isDigitsOnly(width) && TextUtils.isDigitsOnly(height)) {
Main.width = Integer.parseInt(width);
Main.height = Integer.parseInt(height);
}
if (Main.width == 0 || Main.height == 0) {
// dimension initialization
Point point = displayUtil.getCurrentDisplaySize();
if (point != null && point.x > 0 && point.y > 0) {
Main.width = point.x;
Main.height = point.y;
} else {
Main.width = 480;
Main.height = 800;
}
}
int destWidth = Main.width;
int destHeight = Main.height;
byte[] bytes = getScreenImageInBytes(formatInfo.first, destWidth, destHeight, null);
response.send(formatInfo.second, bytes);
} catch (Exception e) {
response.code(500);
response.send(e.toString());
}
}
}
}
19
Source : ThreadPool.java
with MIT License
from ravindu1024
with MIT License
from ravindu1024
/**
* Initialize the http thread pool
*
* @param num number of threads in thread pool
*/
static void initialize(int num) throws InterruptedException {
if (mInstance == null) {
mInstance = new ThreadPool();
mInstance.mThreads = new HandlerThread[num];
for (int i = 0; i < num; i++) {
mInstance.mThreads[i] = new HandlerThread("Velocity_workerThread_" + i);
mInstance.mThreads[i].start();
int count = 0;
while (mInstance.mThreads[i].getLooper() == null && count++ < 10) {
Thread.sleep(50);
}
Looper l = mInstance.mThreads[i].getLooper();
if (mInstance.mThreads[i].getLooper() != null) {
mInstance.mHandlers.add(new Handler(l));
}
}
NetLog.d("initialized threadpool with size : " + num);
}
}
19
Source : FakeClock.java
with Apache License 2.0
from PaulWoitaschek
with Apache License 2.0
from PaulWoitaschek
@Override
public HandlerWrapper createHandler(Looper looper, Callback callback) {
return new ClockHandler(looper, callback);
}
19
Source : DefaultDrmSessionManager.java
with Apache License 2.0
from PaulWoitaschek
with Apache License 2.0
from PaulWoitaschek
private void maybeCreateMediaDrmHandler(Looper playbackLooper) {
if (mediaDrmHandler == null) {
mediaDrmHandler = new MediaDrmHandler(playbackLooper);
}
}
19
Source : DefaultDrmSessionManager.java
with Apache License 2.0
from PaulWoitaschek
with Apache License 2.0
from PaulWoitaschek
// Internal methods.
private void replacedertExpectedPlaybackLooper(Looper playbackLooper) {
replacedertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper);
this.playbackLooper = playbackLooper;
}
19
Source : AndroidSchedulers.java
with MIT License
from nurkiewicz
with MIT License
from nurkiewicz
/**
* A {@link Scheduler} which executes actions on {@code looper}.
*/
public static Scheduler from(Looper looper) {
if (looper == null)
throw new NullPointerException("looper == null");
return new LooperScheduler(looper);
}
19
Source : NonStopIntentService.java
with GNU General Public License v3.0
from NearbyShops
with GNU General Public License v3.0
from NearbyShops
/**
* Created by sumeet on 9/3/17.
*/
public abstract clreplaced NonStopIntentService extends Service {
private String mName;
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
public NonStopIntentService(String name) {
super();
mName = name;
}
private final clreplaced ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent) msg.obj);
// stopSelf(msg.arg1); <-- Removed
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return START_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
*
* @param intent The value preplaceded to {@link
* android.content.Context#startService(Intent)}.
*/
protected abstract void onHandleIntent(Intent intent);
}
19
Source : ForegroundService.java
with GNU General Public License v3.0
from MuntashirAkon
with GNU General Public License v3.0
from MuntashirAkon
public abstract clreplaced ForegroundService extends Service {
private final String name;
private Looper serviceLooper;
private ServiceHandler serviceHandler;
// Handler that receives messages from the thread
private final clreplaced ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent(msg.getData().getParcelable("intent"));
stopSelf(msg.arg1);
}
}
protected ForegroundService(String name) {
this.name = name;
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread(name, Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
Bundle args = new Bundle();
args.putParcelable("intent", intent);
msg.setData(args);
serviceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
protected abstract void onHandleIntent(@Nullable Intent intent);
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
19
Source : MapboxFusedLocationEngineImplTest.java
with MIT License
from mapbox
with MIT License
from mapbox
@Test
public void requestLocationUpdatesOutdoors() {
LocationEngineRequest request = new LocationEngineRequest.Builder(10).setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY).build();
LocationEngineCallback<LocationEngineResult> callback = mock(LocationEngineCallback.clreplaced);
Looper looper = mock(Looper.clreplaced);
when(locationManagerMock.getBestProvider(any(Criteria.clreplaced), anyBoolean())).thenReturn("gps");
engine.requestLocationUpdates(request, callback, looper);
verify(locationManagerMock, times(2)).requestLocationUpdates(anyString(), anyLong(), anyFloat(), any(LocationListener.clreplaced), any(Looper.clreplaced));
}
19
Source : MapboxFusedLocationEngineImplTest.java
with MIT License
from mapbox
with MIT License
from mapbox
@Test
public void requestLocationUpdatesIndoors() {
LocationEngineRequest request = new LocationEngineRequest.Builder(10).setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY).build();
LocationEngineCallback<LocationEngineResult> callback = mock(LocationEngineCallback.clreplaced);
Looper looper = mock(Looper.clreplaced);
when(locationManagerMock.getBestProvider(any(Criteria.clreplaced), anyBoolean())).thenReturn("network");
engine.requestLocationUpdates(request, callback, looper);
verify(locationManagerMock, times(1)).requestLocationUpdates(anyString(), anyLong(), anyFloat(), any(LocationListener.clreplaced), any(Looper.clreplaced));
}
19
Source : AndroidLocationEngineImplTest.java
with MIT License
from mapbox
with MIT License
from mapbox
@Test
public void requestLocationUpdatesBestProviderNull() {
LocationEngineRequest request = new LocationEngineRequest.Builder(10).setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY).build();
LocationEngineCallback<LocationEngineResult> callback = mock(LocationEngineCallback.clreplaced);
Looper looper = mock(Looper.clreplaced);
when(locationManagerMock.getBestProvider(any(Criteria.clreplaced), anyBoolean())).thenReturn(null);
engine.requestLocationUpdates(request, callback, looper);
replacedertThat(androidLocationEngineImpl.currentProvider).isEqualTo("preplacedive");
}
19
Source : LocationEngineProxy.java
with MIT License
from mapbox
with MIT License
from mapbox
@Override
public void requestLocationUpdates(@NonNull LocationEngineRequest request, @NonNull LocationEngineCallback<LocationEngineResult> callback, @Nullable Looper looper) throws SecurityException {
checkNotNull(request, "request == null");
checkNotNull(callback, "callback == null");
locationEngineImpl.requestLocationUpdates(request, getListener(callback), looper == null ? Looper.getMainLooper() : looper);
}
19
Source : AsyncQueryHandler.java
with Apache License 2.0
from Madrapps
with Apache License 2.0
from Madrapps
/**
* A helper clreplaced to help make handling asynchronous {@link ContentResolver}
* queries easier.
*/
public abstract clreplaced AsyncQueryHandler extends Handler {
private static final String TAG = "AsyncQuery";
private static final boolean localLOGV = false;
private static final int EVENT_ARG_QUERY = 1;
private static final int EVENT_ARG_INSERT = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
private static final int EVENT_ARG_BULK_INSERT = 5;
private static Looper sLooper = null;
private final WeakReference<ContentResolver> mResolver;
private Handler mWorkerThreadHandler;
public AsyncQueryHandler(ContentResolver cr) {
super();
mResolver = new WeakReference<>(cr);
synchronized (AsyncQueryHandler.clreplaced) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = createHandler(sLooper);
}
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
/**
* This method begins an asynchronous query. When the query is done
* {@link #onQueryComplete} is called.
*
* @param token A token preplaceded into {@link #onQueryComplete} to identify
* the query.
* @param cookie An object that gets preplaceded into {@link #onQueryComplete}
* @param uri The URI, using the content:// scheme, for the content to
* retrieve.
* @param projection A list of which columns to return. Preplaceding null will
* return all columns, which is discouraged to prevent reading data
* from storage that isn't going to be used.
* @param selection A filter declaring which rows to return, formatted as an
* SQL WHERE clause (excluding the WHERE itself). Preplaceding null will
* return all rows for the given URI.
* @param selectionArgs You may include ?s in selection, which will be
* replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
* @param orderBy How to order the rows, formatted as an SQL ORDER BY
* clause (excluding the ORDER BY itself). Preplaceding null will use the
* default sort order, which may be unordered.
*/
public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.projection = projection;
args.selection = selection;
args.selectionArgs = selectionArgs;
args.orderBy = orderBy;
args.cookie = cookie;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* Attempts to cancel operation that has not already started. Note that
* there is no guarantee that the operation will be canceled. They still may
* result in a call to on[Query/Insert/Update/Delete]Complete after this
* call has completed.
*
* @param token The token representing the operation to be canceled.
* If multiple operations have the same token they will all be canceled.
*/
public final void cancelOperation(int token) {
mWorkerThreadHandler.removeMessages(token);
}
/**
* This method begins an asynchronous insert. When the insert operation is
* done {@link #onInsertComplete} is called.
*
* @param token A token preplaceded into {@link #onInsertComplete} to identify
* the insert operation.
* @param cookie An object that gets preplaceded into {@link #onInsertComplete}
* @param uri the Uri preplaceded to the insert operation.
* @param initialValues the ContentValues parameter preplaceded to the insert operation.
*/
public final void startInsert(int token, Object cookie, Uri uri, ContentValues initialValues) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_INSERT;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.values = initialValues;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous bulk insert. When the insert operation is
* done {@link #onBulkInsertComplete} is called.
*
* @param token A token preplaceded into {@link #onBulkInsertComplete} to identify
* the insert operation.
* @param cookie An object that gets preplaceded into {@link #onBulkInsertComplete}
* @param uri the Uri preplaceded to the insert operation.
* @param initialValues the ContentValues array parameter preplaceded to the insert operation.
*/
public final void startBulkInsert(int token, Object cookie, Uri uri, ContentValues[] initialValues) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_BULK_INSERT;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.valuesArray = initialValues;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous update. When the update operation is
* done {@link #onUpdateComplete} is called.
*
* @param token A token preplaceded into {@link #onUpdateComplete} to identify
* the update operation.
* @param cookie An object that gets preplaceded into {@link #onUpdateComplete}
* @param uri the Uri preplaceded to the update operation.
* @param values the ContentValues parameter preplaceded to the update operation.
*/
public final void startUpdate(int token, Object cookie, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_UPDATE;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.values = values;
args.selection = selection;
args.selectionArgs = selectionArgs;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous delete. When the delete operation is
* done {@link #onDeleteComplete} is called.
*
* @param token A token preplaceded into {@link #onDeleteComplete} to identify
* the delete operation.
* @param cookie An object that gets preplaceded into {@link #onDeleteComplete}
* @param uri the Uri preplaceded to the delete operation.
* @param selection the where clause.
*/
public final void startDelete(int token, Object cookie, Uri uri, String selection, String[] selectionArgs) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_DELETE;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.selection = selection;
args.selectionArgs = selectionArgs;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* Called when an asynchronous query is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startQuery}.
* @param cookie the cookie object preplaceded in from {@link #startQuery}.
* @param cursor The cursor holding the results from the query.
*/
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// Empty
}
/**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startInsert}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startInsert}.
* @param uri the uri returned from the insert operation.
*/
protected void onInsertComplete(int token, Object cookie, Uri uri) {
// Empty
}
/**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startInsert}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startInsert}.
* @param result the result returned from the bulk insert operation
*/
protected void onBulkInsertComplete(int token, Object cookie, int result) {
// Empty
}
/**
* Called when an asynchronous update is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startUpdate}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startUpdate}.
* @param result the result returned from the update operation
*/
protected void onUpdateComplete(int token, Object cookie, int result) {
// Empty
}
/**
* Called when an asynchronous delete is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startDelete}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startDelete}.
* @param result the result returned from the delete operation
*/
protected void onDeleteComplete(int token, Object cookie, int result) {
// Empty
}
@Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
if (localLOGV) {
Log.d(TAG, "AsyncQueryHandler.handleMessage: msg.what=" + msg.what + ", msg.arg1=" + msg.arg1);
}
int token = msg.what;
int event = msg.arg1;
// preplaced token back to caller on each callback.
switch(event) {
case EVENT_ARG_QUERY:
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;
case EVENT_ARG_BULK_INSERT:
onBulkInsertComplete(token, args.cookie, (Integer) args.result);
break;
case EVENT_ARG_UPDATE:
onUpdateComplete(token, args.cookie, (Integer) args.result);
break;
case EVENT_ARG_DELETE:
onDeleteComplete(token, args.cookie, (Integer) args.result);
break;
}
}
protected static final clreplaced WorkerArgs {
public Uri uri;
public Handler handler;
public String[] projection;
public String selection;
public String[] selectionArgs;
public String orderBy;
public Object result;
public Object cookie;
public ContentValues values;
public ContentValues[] valuesArray;
}
protected clreplaced WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
final ContentResolver resolver = mResolver.get();
if (resolver == null)
return;
WorkerArgs args = (WorkerArgs) msg.obj;
int token = msg.what;
int event = msg.arg1;
switch(event) {
case EVENT_ARG_QUERY:
Cursor cursor;
try {
cursor = resolver.query(args.uri, args.projection, args.selection, args.selectionArgs, args.orderBy);
// Calling getCount() causes the cursor window to be filled,
// which will make the first access on the main thread a lot faster.
if (cursor != null) {
cursor.getCount();
}
} catch (Exception e) {
Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e);
cursor = null;
}
args.result = cursor;
break;
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
case EVENT_ARG_BULK_INSERT:
args.result = resolver.bulkInsert(args.uri, args.valuesArray);
break;
case EVENT_ARG_UPDATE:
args.result = resolver.update(args.uri, args.values, args.selection, args.selectionArgs);
break;
case EVENT_ARG_DELETE:
args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
break;
}
// preplaceding the original token value back to the caller
// on top of the event values in arg1.
Message reply = args.handler.obtainMessage(token);
reply.obj = args;
reply.arg1 = msg.arg1;
if (localLOGV) {
Log.d(TAG, "WorkerHandler.handleMsg: msg.arg1=" + msg.arg1 + ", reply.what=" + reply.what);
}
reply.sendToTarget();
}
}
}
19
Source : AsyncQueryHandler.java
with Apache License 2.0
from Madrapps
with Apache License 2.0
from Madrapps
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
19
Source : WalletService.java
with Apache License 2.0
from m2049r
with Apache License 2.0
from m2049r
@Override
public void onCreate() {
// We are using a HandlerThread and a Looper to avoid loading and closing
// concurrency
MoneroHandlerThread thread = new MoneroHandlerThread("WalletService", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
final Looper serviceLooper = thread.getLooper();
mServiceHandler = new WalletService.ServiceHandler(serviceLooper);
Timber.d("Service created");
}
19
Source : MoneroHandlerThread.java
with Apache License 2.0
from m2049r
with Apache License 2.0
from m2049r
/**
* Handy clreplaced for starting a new thread that has a looper. The looper can then be
* used to create handler clreplacedes. Note that start() must still be called.
* The started Thread has a stck size of STACK_SIZE (=5MB)
*/
public clreplaced MoneroHandlerThread extends Thread {
// from src/cryptonote_config.h
static public final long THREAD_STACK_SIZE = 5 * 1024 * 1024;
private int mPriority;
private int mTid = -1;
private Looper mLooper;
public MoneroHandlerThread(String name) {
super(null, null, name, THREAD_STACK_SIZE);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a MoneroHandlerThread.
*
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
MoneroHandlerThread(String name, int priority) {
super(null, null, name, THREAD_STACK_SIZE);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
private void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper replacedociated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
*
* @return The looper.
*/
Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p clreplaced="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
19
Source : MoneroHandlerThread.java
with Apache License 2.0
from m2049r
with Apache License 2.0
from m2049r
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p clreplaced="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
19
Source : MoneroHandlerThread.java
with Apache License 2.0
from m2049r
with Apache License 2.0
from m2049r
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
19
Source : InputMonitor.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory) {
if (mInputConsumers.containsKey(name)) {
throw new IllegalStateException("Existing input consumer found with name: " + name);
}
final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService, this, looper, name, inputEventReceiverFactory, Process.myPid(), UserHandle.SYSTEM);
addInputConsumer(name, consumer);
return consumer;
}
19
Source : HdmiCecFeatureAction.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
private ActionTimer createActionTimer(Looper looper) {
return new ActionTimerHandler(looper);
}
19
Source : Choreographer.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
/**
* Coordinates the timing of animations, input and drawing.
* <p>
* The creplacedographer receives timing pulses (such as vertical synchronization)
* from the display subsystem then schedules work to occur as part of rendering
* the next display frame.
* </p><p>
* Applications typically interact with the creplacedographer indirectly using
* higher level abstractions in the animation framework or the view hierarchy.
* Here are some examples of things you can do using the higher-level APIs.
* </p>
* <ul>
* <li>To post an animation to be processed on a regular time basis synchronized with
* display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
* <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
* frame, use {@link View#postOnAnimation}.</li>
* <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
* frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
* <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
* next display frame, use {@link View#postInvalidateOnAnimation()} or
* {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
* <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
* sync with display frame rendering, do nothing. This already happens automatically.
* {@link View#onDraw} will be called at the appropriate time.</li>
* </ul>
* <p>
* However, there are a few cases where you might want to use the functions of the
* creplacedographer directly in your application. Here are some examples.
* </p>
* <ul>
* <li>If your application does its rendering in a different thread, possibly using GL,
* or does not use the animation framework or view hierarchy at all
* and you want to ensure that it is appropriately synchronized with the display, then use
* {@link Creplacedographer#postFrameCallback}.</li>
* <li>... and that's about it.</li>
* </ul>
* <p>
* Each {@link Looper} thread has its own creplacedographer. Other threads can
* post callbacks to run on the creplacedographer but they will run on the {@link Looper}
* to which the creplacedographer belongs.
* </p>
*/
public final clreplaced Creplacedographer {
private static final String TAG = "Creplacedographer";
// Prints debug messages about jank which was detected (low volume).
private static final boolean DEBUG_JANK = false;
// Prints debug messages about every frame and callback registered (high volume).
private static final boolean DEBUG_FRAMES = false;
// The default amount of time in ms between animation frames.
// When vsync is not enabled, we want to have some idea of how long we should
// wait before posting the next animation message. It is important that the
// default value be less than the true inter-frame delay on all devices to avoid
// situations where we might skip frames by waiting too long (we must compensate
// for jitter and hardware variations). Regardless of this value, the animation
// and display loop is ultimately rate-limited by how fast new graphics buffers can
// be dequeued.
private static final long DEFAULT_FRAME_DELAY = 10;
// The number of milliseconds between animation frames.
private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
// Thread local storage for the creplacedographer.
private static final ThreadLocal<Creplacedographer> sThreadInstance = new ThreadLocal<Creplacedographer>() {
@Override
protected Creplacedographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
Creplacedographer creplacedographer = new Creplacedographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = creplacedographer;
}
return creplacedographer;
}
};
private static volatile Creplacedographer mMainInstance;
// Thread local storage for the SF creplacedographer.
private static final ThreadLocal<Creplacedographer> sSfThreadInstance = new ThreadLocal<Creplacedographer>() {
@Override
protected Creplacedographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Creplacedographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
}
};
// Enable/disable vsync for animations and drawing.
private static final boolean USE_VSYNC = SystemProperties.getBoolean("debug.creplacedographer.vsync", true);
// Enable/disable using the frame time instead of returning now.
private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean("debug.creplacedographer.frametime", true);
// Set a limit to warn about skipped frames.
// Skipped frames imply jank.
private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt("debug.creplacedographer.skipwarning", 30);
private static final int MSG_DO_FRAME = 0;
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
// All frame callbacks posted by applications have this token.
private static final Object FRAME_CALLBACK_TOKEN = new Object() {
public String toString() {
return "FRAME_CALLBACK_TOKEN";
}
};
private final Object mLock = new Object();
private final Looper mLooper;
private final FrameHandler mHandler;
// The display event receiver can only be accessed by the looper thread to which
// it is attached. We take care to ensure that we post message to the looper
// if appropriate when interacting with the display event receiver.
private final FrameDisplayEventReceiver mDisplayEventReceiver;
private CallbackRecord mCallbackPool;
private final CallbackQueue[] mCallbackQueues;
private boolean mFrameScheduled;
private boolean mCallbacksRunning;
private long mLastFrameTimeNanos;
private long mFrameIntervalNanos;
private boolean mDebugPrintNextFrameTimeDelta;
private int mFPSDivisor = 1;
/**
* Contains information about the current frame for jank-tracking,
* mainly timings of key events along with a bit of metadata about
* view tree state
*
* TODO: Is there a better home for this? Currently Creplacedographer
* is the only one with CALLBACK_ANIMATION start time, hence why this
* resides here.
*
* @hide
*/
FrameInfo mFrameInfo = new FrameInfo();
/**
* Must be kept in sync with CALLBACK_* ints below, used to index into this array.
* @hide
*/
private static final String[] CALLBACK_TRACE_replacedLES = { "input", "animation", "traversal", "commit" };
/**
* Callback type: Input callback. Runs first.
* @hide
*/
public static final int CALLBACK_INPUT = 0;
/**
* Callback type: Animation callback. Runs before traversals.
* @hide
*/
@TestApi
public static final int CALLBACK_ANIMATION = 1;
/**
* Callback type: Traversal callback. Handles layout and draw. Runs
* after all other asynchronous messages have been handled.
* @hide
*/
public static final int CALLBACK_TRAVERSAL = 2;
/**
* Callback type: Commit callback. Handles post-draw operations for the frame.
* Runs after traversal completes. The {@link #getFrameTime() frame time} reported
* during this callback may be updated to reflect delays that occurred while
* traversals were in progress in case heavy layout operations caused some frames
* to be skipped. The frame time reported during this callback provides a better
* estimate of the start time of the frame in which animations (and other updates
* to the view hierarchy state) actually took effect.
* @hide
*/
public static final int CALLBACK_COMMIT = 3;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
private Creplacedographer(Looper looper, int vsyncSource) {
mLooper = looper;
// 处理事件
mHandler = new FrameHandler(looper);
// 4.1 之后默认为 true,
// FrameDisplayEventReceiver 是个 vsync 事件接收器
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
// 一帧的时间,60pfs 的话就是 16.7ms
mFrameIntervalNanos = (long) (1000000000 / getRefreshRate());
// 回调队列
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
// b/68769804: For low FPS experiments.
setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}
private static float getRefreshRate() {
DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(Display.DEFAULT_DISPLAY);
return di.getMode().getRefreshRate();
}
/**
* Gets the creplacedographer for the calling thread. Must be called from
* a thread that already has a {@link android.os.Looper} replacedociated with it.
*
* @return The creplacedographer for this thread.
* 当前线程一般就是主线程
* @throws IllegalStateException if the thread does not have a looper.
*/
public static Creplacedographer getInstance() {
return sThreadInstance.get();
}
/**
* @hide
*/
public static Creplacedographer getSfInstance() {
return sSfThreadInstance.get();
}
/**
* @return The Creplacedographer of the main thread, if it exists, or {@code null} otherwise.
* @hide
*/
public static Creplacedographer getMainThreadInstance() {
return mMainInstance;
}
/**
* Destroys the calling thread's creplacedographer
* @hide
*/
public static void releaseInstance() {
Creplacedographer old = sThreadInstance.get();
sThreadInstance.remove();
old.dispose();
}
private void dispose() {
mDisplayEventReceiver.dispose();
}
/**
* The amount of time, in milliseconds, between each frame of the animation.
* <p>
* This is a requested time that the animation will attempt to honor, but the actual delay
* between frames may be different, depending on system load and capabilities. This is a static
* function because the same delay will be applied to all animations, since they are all
* run off of a single timing loop.
* </p><p>
* The frame delay may be ignored when the animation system uses an external timing
* source, such as the display refresh rate (vsync), to govern animations.
* </p>
*
* @return the requested time between frames, in milliseconds
* @hide
*/
@TestApi
public static long getFrameDelay() {
return sFrameDelay;
}
/**
* The amount of time, in milliseconds, between each frame of the animation.
* <p>
* This is a requested time that the animation will attempt to honor, but the actual delay
* between frames may be different, depending on system load and capabilities. This is a static
* function because the same delay will be applied to all animations, since they are all
* run off of a single timing loop.
* </p><p>
* The frame delay may be ignored when the animation system uses an external timing
* source, such as the display refresh rate (vsync), to govern animations.
* </p>
*
* @param frameDelay the requested time between frames, in milliseconds
* @hide
*/
@TestApi
public static void setFrameDelay(long frameDelay) {
sFrameDelay = frameDelay;
}
/**
* Subtracts typical frame delay time from a delay interval in milliseconds.
* <p>
* This method can be used to compensate for animation delay times that have baked
* in replacedumptions about the frame delay. For example, it's quite common for code to
* replacedume a 60Hz frame time and bake in a 16ms delay. When we call
* {@link #postAnimationCallbackDelayed} we want to know how long to wait before
* posting the animation callback but let the animation timer take care of the remaining
* frame delay time.
* </p><p>
* This method is somewhat conservative about how much of the frame delay it
* subtracts. It uses the same value returned by {@link #getFrameDelay} which by
* default is 10ms even though many parts of the system replacedume 16ms. Consequently,
* we might still wait 6ms before posting an animation callback that we want to run
* on the next frame, but this is much better than waiting a whole 16ms and likely
* missing the deadline.
* </p>
*
* @param delayMillis The original delay time including an replacedumed frame delay.
* @return The adjusted delay time with the replacedumed frame delay subtracted out.
* @hide
*/
public static long subtractFrameDelay(long delayMillis) {
final long frameDelay = sFrameDelay;
return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
}
/**
* @return The refresh rate as the nanoseconds between frames
* @hide
*/
public long getFrameIntervalNanos() {
return mFrameIntervalNanos;
}
void dump(String prefix, PrintWriter writer) {
String innerPrefix = prefix + " ";
writer.print(prefix);
writer.println("Creplacedographer:");
writer.print(innerPrefix);
writer.print("mFrameScheduled=");
writer.println(mFrameScheduled);
writer.print(innerPrefix);
writer.print("mLastFrameTime=");
writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
}
/**
* Posts a callback to run on the next frame.
* <p>
* The callback runs once then is automatically removed.
* </p>
*
* @param callbackType The callback type.
* @param action The callback action to run during the next frame.
* @param token The callback token, or null if none.
*
* @see #removeCallbacks
* @hide
*/
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
/**
* Posts a callback to run on the next frame after the specified delay.
* <p>
* The callback runs once then is automatically removed.
* </p>
*
* @param callbackType The callback type.
* @param action The callback action to run during the next frame after the specified delay.
* @param token The callback token, or null if none.
* @param delayMillis The delay time in milliseconds.
*
* @see #removeCallback
* @hide
*/
@TestApi
public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType + ", action=" + action + ", token=" + token + ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
// 立即执行
scheduleFrameLocked(now);
} else {
// 延迟执行
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
/**
* Removes callbacks that have the specified action and token.
*
* @param callbackType The callback type.
* @param action The action property of the callbacks to remove, or null to remove
* callbacks with any action.
* @param token The token property of the callbacks to remove, or null to remove
* callbacks with any token.
*
* @see #postCallback
* @see #postCallbackDelayed
* @hide
*/
@TestApi
public void removeCallbacks(int callbackType, Runnable action, Object token) {
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
removeCallbacksInternal(callbackType, action, token);
}
private void removeCallbacksInternal(int callbackType, Object action, Object token) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RemoveCallbacks: type=" + callbackType + ", action=" + action + ", token=" + token);
}
synchronized (mLock) {
mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
if (action != null && token == null) {
mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
}
}
}
/**
* Posts a frame callback to run on the next frame.
* <p>
* The callback runs once then is automatically removed.
* </p>
*
* @param callback The frame callback to run during the next frame.
*
* @see #postFrameCallbackDelayed
* @see #removeFrameCallback
*/
public void postFrameCallback(FrameCallback callback) {
postFrameCallbackDelayed(callback, 0);
}
/**
* Posts a frame callback to run on the next frame after the specified delay.
* <p>
* The callback runs once then is automatically removed.
* </p>
*
* @param callback The frame callback to run during the next frame.
* @param delayMillis The delay time in milliseconds.
*
* @see #postFrameCallback
* @see #removeFrameCallback
*/
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN, delayMillis);
}
/**
* Removes a previously posted frame callback.
*
* @param callback The frame callback to remove.
*
* @see #postFrameCallback
* @see #postFrameCallbackDelayed
*/
public void removeFrameCallback(FrameCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
}
/**
* Gets the time when the current frame started.
* <p>
* This method provides the time in milliseconds when the frame started being rendered.
* The frame time provides a stable time base for synchronizing animations
* and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
* or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
* time helps to reduce inter-frame jitter because the frame time is fixed at the time
* the frame was scheduled to start, regardless of when the animations or drawing
* callback actually runs. All callbacks that run as part of rendering a frame will
* observe the same frame time so using the frame time also helps to synchronize effects
* that are performed by different callbacks.
* </p><p>
* Please note that the framework already takes care to process animations and
* drawing using the frame time as a stable time base. Most applications should
* not need to use the frame time information directly.
* </p><p>
* This method should only be called from within a callback.
* </p>
*
* @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
*
* @throws IllegalStateException if no frame is in progress.
* @hide
*/
public long getFrameTime() {
return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
}
/**
* Same as {@link #getFrameTime()} but with nanosecond precision.
*
* @return The frame start time, in the {@link System#nanoTime()} time base.
*
* @throws IllegalStateException if no frame is in progress.
* @hide
*/
public long getFrameTimeNanos() {
synchronized (mLock) {
if (!mCallbacksRunning) {
throw new IllegalStateException("This method must only be called as " + "part of a callback while a frame is in progress.");
}
return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
}
}
/**
* Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
* whether callbacks are currently running.
* @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
* @hide
*/
public long getLastFrameTimeNanos() {
synchronized (mLock) {
return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
}
}
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
// 如果是当前线程,直接申请 vsync,否则通过 handler 通信
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
// 未开启 vsync,4.1 之后默认开启
final long nextFrameTime = Math.max(mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
void setFPSDivisor(int divisor) {
if (divisor <= 0)
divisor = 1;
mFPSDivisor = divisor;
ThreadedRenderer.setFPSDivisor(divisor);
}
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
// no work to do
return;
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: " + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
// 计算超时时间
// frameTimeNanos 是 vsync 信号回调的时间,startNanos 是当前时间戳
// 相减得到主线程的耗时时间
final long jitterNanos = startNanos - frameTimeNanos;
// mFrameIntervalNanos 是一帧的时间
if (jitterNanos >= mFrameIntervalNanos) {
// 计算掉了多少帧
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
// 掉帧超过 30 帧,打印 log
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " + "which is more than the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + "Skipping " + skippedFrames + " frames and setting frame " + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a " + "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
scheduleVsyncLocked();
return;
}
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Creplacedographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
// doCallBacks() 开始执行回调
mFrameInfo.markInputHandlingStart();
doCallbacks(Creplacedographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Creplacedographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Creplacedographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Creplacedographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took " + (endNanos - startNanos) * 0.000001f + " ms, latency " + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = System.nanoTime();
// 根据 callbackType 找到对应的 CallbackRecord 对象
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
// Update the frame time if necessary when committing the frame.
// We only update the frame time if we are more than 2 frames late reaching
// the commit phase. This ensures that the frame time which is observed by the
// callbacks will always increase from one frame to the next and never repeat.
// We never want the next frame's starting frame time to end up being less than
// or equal to the previous frame's commit frame time. Keep in mind that the
// next frame has most likely already been scheduled by now so we play it
// safe by ensuring the commit time is always at least one frame behind.
if (callbackType == Creplacedographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos + mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f) + " ms which is more than twice the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + "Setting frame time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
}
}
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_replacedLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType + ", action=" + c.action + ", token=" + c.token + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
void doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}
void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
private boolean isRunningOnLooperThreadLocked() {
return Looper.myLooper() == mLooper;
}
private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = mCallbackPool;
if (callback == null) {
callback = new CallbackRecord();
} else {
mCallbackPool = callback.next;
callback.next = null;
}
callback.dueTime = dueTime;
callback.action = action;
callback.token = token;
return callback;
}
private void recycleCallbackLocked(CallbackRecord callback) {
callback.action = null;
callback.token = null;
callback.next = mCallbackPool;
mCallbackPool = callback;
}
/**
* Implement this interface to receive a callback when a new display frame is
* being rendered. The callback is invoked on the {@link Looper} thread to
* which the {@link Creplacedographer} is attached.
*/
public interface FrameCallback {
/**
* Called when a new display frame is being rendered.
* <p>
* This method provides the time in nanoseconds when the frame started being rendered.
* The frame time provides a stable time base for synchronizing animations
* and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
* or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
* time helps to reduce inter-frame jitter because the frame time is fixed at the time
* the frame was scheduled to start, regardless of when the animations or drawing
* callback actually runs. All callbacks that run as part of rendering a frame will
* observe the same frame time so using the frame time also helps to synchronize effects
* that are performed by different callbacks.
* </p><p>
* Please note that the framework already takes care to process animations and
* drawing using the frame time as a stable time base. Most applications should
* not need to use the frame time information directly.
* </p>
*
* @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
* in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
* to convert it to the {@link SystemClock#uptimeMillis()} time base.
*/
public void doFrame(long frameTimeNanos);
}
private final clreplaced FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
// 申请 vsync 信号
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
// 执行延时消息
doScheduleCallback(msg.arg1);
break;
}
}
}
private final clreplaced FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// Ignore vsync from secondary display.
// This can be problematic because the call to scheduleVsync() is a one-shot.
// We need to ensure that we will still receive the vsync from the primary
// display which is the one we really care about. Ideally we should schedule
// vsync for a particular display.
// At this time Surface Flinger won't send us vsyncs for secondary displays
// but that could change in the future so let's log a message to help us remember
// that we need to fix this.
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Log.d(TAG, "Received vsync from secondary display, but we don't support " + "this case yet. Creplacedographer needs a way to explicitly request " + "vsync for a specific display to ensure it doesn't lose track " + "of its scheduled vsync.");
scheduleVsync();
return;
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps
// earlier than the frame time, then the vsync event will be processed immediately.
// Otherwise, messages that predate the vsync event will be handled first.
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) + " ms in the future! Check that graphics HAL is generating vsync " + "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
// 这里传入的是 this,会回调本身的 run() 方法
Message msg = Message.obtain(mHandler, this);
// 这是一个异步消息,保证优先执行
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
private static final clreplaced CallbackRecord {
public CallbackRecord next;
public long dueTime;
// Runnable or FrameCallback
public Object action;
public Object token;
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback) action).doFrame(frameTimeNanos);
} else {
((Runnable) action).run();
}
}
}
private final clreplaced CallbackQueue {
private CallbackRecord mHead;
public boolean hasDueCallbacksLocked(long now) {
return mHead != null && mHead.dueTime <= now;
}
public CallbackRecord extractDueCallbacksLocked(long now) {
CallbackRecord callbacks = mHead;
if (callbacks == null || callbacks.dueTime > now) {
return null;
}
CallbackRecord last = callbacks;
CallbackRecord next = last.next;
while (next != null) {
if (next.dueTime > now) {
last.next = null;
break;
}
last = next;
next = next.next;
}
mHead = next;
return callbacks;
}
public void addCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
CallbackRecord entry = mHead;
if (entry == null) {
mHead = callback;
return;
}
if (dueTime < entry.dueTime) {
callback.next = entry;
mHead = callback;
return;
}
while (entry.next != null) {
if (dueTime < entry.next.dueTime) {
callback.next = entry.next;
break;
}
entry = entry.next;
}
entry.next = callback;
}
public void removeCallbacksLocked(Object action, Object token) {
CallbackRecord predecessor = null;
for (CallbackRecord callback = mHead; callback != null; ) {
final CallbackRecord next = callback.next;
if ((action == null || callback.action == action) && (token == null || callback.token == token)) {
if (predecessor != null) {
predecessor.next = next;
} else {
mHead = next;
}
recycleCallbackLocked(callback);
} else {
predecessor = callback;
}
callback = next;
}
}
}
}
19
Source : AccessibilityManager.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
/**
* Requests feedback interruption from all accessibility services.
*/
public void interrupt() {
final IAccessibilityManager service;
final int userId;
synchronized (mLock) {
service = getServiceLocked();
if (service == null) {
return;
}
if (!isEnabled()) {
Looper myLooper = Looper.myLooper();
if (myLooper == Looper.getMainLooper()) {
throw new IllegalStateException("Accessibility off. Did you forget to check that?");
} else {
// If we're not running on the thread with the main looper, it's possible for
// the state of accessibility to change between checking isEnabled and
// calling this method. So just log the error rather than throwing the
// exception.
Log.e(LOG_TAG, "Interrupt called with accessibility disabled");
return;
}
}
userId = mUserId;
}
try {
service.interrupt(userId);
if (DEBUG) {
Log.i(LOG_TAG, "Requested interrupt from all services");
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while requesting interrupt from all services. ", re);
}
}
19
Source : AsyncQueryHandler.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
/**
* A helper clreplaced to help make handling asynchronous {@link ContentResolver}
* queries easier.
*/
public abstract clreplaced AsyncQueryHandler extends Handler {
private static final String TAG = "AsyncQuery";
private static final boolean localLOGV = false;
private static final int EVENT_ARG_QUERY = 1;
private static final int EVENT_ARG_INSERT = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
/* package */
final WeakReference<ContentResolver> mResolver;
private static Looper sLooper = null;
private Handler mWorkerThreadHandler;
protected static final clreplaced WorkerArgs {
public Uri uri;
public Handler handler;
public String[] projection;
public String selection;
public String[] selectionArgs;
public String orderBy;
public Object result;
public Object cookie;
public ContentValues values;
}
protected clreplaced WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
final ContentResolver resolver = mResolver.get();
if (resolver == null)
return;
WorkerArgs args = (WorkerArgs) msg.obj;
int token = msg.what;
int event = msg.arg1;
switch(event) {
case EVENT_ARG_QUERY:
Cursor cursor;
try {
cursor = resolver.query(args.uri, args.projection, args.selection, args.selectionArgs, args.orderBy);
// Calling getCount() causes the cursor window to be filled,
// which will make the first access on the main thread a lot faster.
if (cursor != null) {
cursor.getCount();
}
} catch (Exception e) {
Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e);
cursor = null;
}
args.result = cursor;
break;
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
case EVENT_ARG_UPDATE:
args.result = resolver.update(args.uri, args.values, args.selection, args.selectionArgs);
break;
case EVENT_ARG_DELETE:
args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
break;
}
// preplaceding the original token value back to the caller
// on top of the event values in arg1.
Message reply = args.handler.obtainMessage(token);
reply.obj = args;
reply.arg1 = msg.arg1;
if (localLOGV) {
Log.d(TAG, "WorkerHandler.handleMsg: msg.arg1=" + msg.arg1 + ", reply.what=" + reply.what);
}
reply.sendToTarget();
}
}
public AsyncQueryHandler(ContentResolver cr) {
super();
mResolver = new WeakReference<ContentResolver>(cr);
synchronized (AsyncQueryHandler.clreplaced) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = createHandler(sLooper);
}
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
/**
* This method begins an asynchronous query. When the query is done
* {@link #onQueryComplete} is called.
*
* @param token A token preplaceded into {@link #onQueryComplete} to identify
* the query.
* @param cookie An object that gets preplaceded into {@link #onQueryComplete}
* @param uri The URI, using the content:// scheme, for the content to
* retrieve.
* @param projection A list of which columns to return. Preplaceding null will
* return all columns, which is discouraged to prevent reading data
* from storage that isn't going to be used.
* @param selection A filter declaring which rows to return, formatted as an
* SQL WHERE clause (excluding the WHERE itself). Preplaceding null will
* return all rows for the given URI.
* @param selectionArgs You may include ?s in selection, which will be
* replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
* @param orderBy How to order the rows, formatted as an SQL ORDER BY
* clause (excluding the ORDER BY itself). Preplaceding null will use the
* default sort order, which may be unordered.
*/
public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.projection = projection;
args.selection = selection;
args.selectionArgs = selectionArgs;
args.orderBy = orderBy;
args.cookie = cookie;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* Attempts to cancel operation that has not already started. Note that
* there is no guarantee that the operation will be canceled. They still may
* result in a call to on[Query/Insert/Update/Delete]Complete after this
* call has completed.
*
* @param token The token representing the operation to be canceled.
* If multiple operations have the same token they will all be canceled.
*/
public final void cancelOperation(int token) {
mWorkerThreadHandler.removeMessages(token);
}
/**
* This method begins an asynchronous insert. When the insert operation is
* done {@link #onInsertComplete} is called.
*
* @param token A token preplaceded into {@link #onInsertComplete} to identify
* the insert operation.
* @param cookie An object that gets preplaceded into {@link #onInsertComplete}
* @param uri the Uri preplaceded to the insert operation.
* @param initialValues the ContentValues parameter preplaceded to the insert operation.
*/
public final void startInsert(int token, Object cookie, Uri uri, ContentValues initialValues) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_INSERT;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.values = initialValues;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous update. When the update operation is
* done {@link #onUpdateComplete} is called.
*
* @param token A token preplaceded into {@link #onUpdateComplete} to identify
* the update operation.
* @param cookie An object that gets preplaceded into {@link #onUpdateComplete}
* @param uri the Uri preplaceded to the update operation.
* @param values the ContentValues parameter preplaceded to the update operation.
*/
public final void startUpdate(int token, Object cookie, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_UPDATE;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.values = values;
args.selection = selection;
args.selectionArgs = selectionArgs;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* This method begins an asynchronous delete. When the delete operation is
* done {@link #onDeleteComplete} is called.
*
* @param token A token preplaceded into {@link #onDeleteComplete} to identify
* the delete operation.
* @param cookie An object that gets preplaceded into {@link #onDeleteComplete}
* @param uri the Uri preplaceded to the delete operation.
* @param selection the where clause.
*/
public final void startDelete(int token, Object cookie, Uri uri, String selection, String[] selectionArgs) {
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_DELETE;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.cookie = cookie;
args.selection = selection;
args.selectionArgs = selectionArgs;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* Called when an asynchronous query is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startQuery}.
* @param cookie the cookie object preplaceded in from {@link #startQuery}.
* @param cursor The cursor holding the results from the query.
*/
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// Empty
}
/**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startInsert}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startInsert}.
* @param uri the uri returned from the insert operation.
*/
protected void onInsertComplete(int token, Object cookie, Uri uri) {
// Empty
}
/**
* Called when an asynchronous update is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startUpdate}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startUpdate}.
* @param result the result returned from the update operation
*/
protected void onUpdateComplete(int token, Object cookie, int result) {
// Empty
}
/**
* Called when an asynchronous delete is completed.
*
* @param token the token to identify the query, preplaceded in from
* {@link #startDelete}.
* @param cookie the cookie object that's preplaceded in from
* {@link #startDelete}.
* @param result the result returned from the delete operation
*/
protected void onDeleteComplete(int token, Object cookie, int result) {
// Empty
}
@Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
if (localLOGV) {
Log.d(TAG, "AsyncQueryHandler.handleMessage: msg.what=" + msg.what + ", msg.arg1=" + msg.arg1);
}
int token = msg.what;
int event = msg.arg1;
// preplaced token back to caller on each callback.
switch(event) {
case EVENT_ARG_QUERY:
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;
case EVENT_ARG_UPDATE:
onUpdateComplete(token, args.cookie, (Integer) args.result);
break;
case EVENT_ARG_DELETE:
onDeleteComplete(token, args.cookie, (Integer) args.result);
break;
}
}
}
19
Source : IntentService.java
with Apache License 2.0
from lulululbj
with Apache License 2.0
from lulululbj
/**
* IntentService is a base clreplaced for {@link Service}s that handle asynchronous
* requests (expressed as {@link Intent}s) on demand. Clients send requests
* through {@link android.content.Context#startService(Intent)} calls; the
* service is started as needed, handles each Intent in turn using a worker
* thread, and stops itself when it runs out of work.
*
* <p>This "work queue processor" pattern is commonly used to offload tasks
* from an application's main thread. The IntentService clreplaced exists to
* simplify this pattern and take care of the mechanics. To use it, extend
* IntentService and implement {@link #onHandleIntent(Intent)}. IntentService
* will receive the Intents, launch a worker thread, and stop the service as
* appropriate.
*
* <p>All requests are handled on a single worker thread -- they may take as
* long as necessary (and will not block the application's main loop), but
* only one request will be processed at a time.
*
* <p clreplaced="note"><b>Note:</b> IntentService is subject to all the
* <a href="/preview/features/background.html">background execution limits</a>
* imposed with Android 8.0 (API level 26). In most cases, you are better off
* using {@link android.support.v4.app.JobIntentService}, which uses jobs
* instead of services when running on Android 8.0 or higher.
* </p>
*
* <div clreplaced="special reference">
* <h3>Developer Guides</h3>
* <p>For a detailed discussion about how to create services, read the
* <a href="{@docRoot}guide/components/services.html">Services</a> developer
* guide.</p>
* </div>
*
* @see android.support.v4.app.JobIntentService
* @see android.os.AsyncTask
*/
public abstract clreplaced IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final clreplaced ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent) msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclreplaced's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value preplaceded to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
See More Examples