You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
implement AlarmManager and JobScheduler
This is needed for the bootstrap job when setting up WhatsApp in companion device mode. The implementation is based on `Handler.postDelayed()`, so jobs and alarms are not persistent for now.
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
package android.app;
|
package android.app;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ConfigurationInfo;
|
import android.content.pm.ConfigurationInfo;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@@ -14,6 +16,13 @@ public class ActivityManager {
|
|||||||
|
|
||||||
public static class RunningAppProcessInfo{
|
public static class RunningAppProcessInfo{
|
||||||
public int importance;
|
public int importance;
|
||||||
|
public int pid;
|
||||||
|
public String processName;
|
||||||
|
|
||||||
|
private RunningAppProcessInfo(int pid, String processName) {
|
||||||
|
this.pid = pid;
|
||||||
|
this.processName = processName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TaskDescription {
|
public static class TaskDescription {
|
||||||
@@ -21,7 +30,7 @@ public class ActivityManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<RunningAppProcessInfo> getRunningAppProcesses() {
|
public List<RunningAppProcessInfo> getRunningAppProcesses() {
|
||||||
return null;
|
return Arrays.asList(new RunningAppProcessInfo(Process.myPid(), Context.this_application.getPackageName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLowRamDevice() {return false;}
|
public boolean isLowRamDevice() {return false;}
|
||||||
|
|||||||
@@ -1,13 +1,51 @@
|
|||||||
package android.app;
|
package android.app;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
public class AlarmManager {
|
public class AlarmManager {
|
||||||
public void cancel(PendingIntent operation) {}
|
private static final String TAG = "AlarmManager";
|
||||||
|
|
||||||
public void setInexactRepeating(int type, long triggerTime, long interval, PendingIntent operation) {}
|
public void cancel(PendingIntent operation) {
|
||||||
|
Slog.i(TAG, "cancel(" + operation + ") called");
|
||||||
public void setExact(int type, long triggerTime, PendingIntent operation) {}
|
}
|
||||||
|
|
||||||
public void set(int type, long triggerTime, PendingIntent operation) {}
|
public void setInexactRepeating(int type, long triggerTime, long interval, PendingIntent operation) {
|
||||||
|
Slog.i(TAG, "setInexactRepeating(" + type + ", " + triggerTime + ", " + interval + ", " + operation + ") called");
|
||||||
public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {}
|
long delay = triggerTime - ((type == 2 || type == 3) ? SystemClock.elapsedRealtime() : System.currentTimeMillis());
|
||||||
|
Slog.i(TAG, "setInexactRepeating() delay: " + DateUtils.formatElapsedTime(delay) + " interval: " + DateUtils.formatElapsedTime(interval));
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Slog.i(TAG, "delivering repeating alarm: " + operation);
|
||||||
|
operation.send();
|
||||||
|
handler.postDelayed(this, interval);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExact(int type, long triggerTime, PendingIntent operation) {
|
||||||
|
Slog.i(TAG, "setExact(" + type + ", " + triggerTime + ", " + operation + ") called");
|
||||||
|
long delay = triggerTime - ((type == 2 || type == 3) ? SystemClock.elapsedRealtime() : System.currentTimeMillis());
|
||||||
|
Slog.i(TAG, "setExact() delay: " + DateUtils.formatElapsedTime(delay));
|
||||||
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Slog.i(TAG, "delivering alarm: " + operation);
|
||||||
|
operation.send();
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int type, long triggerTime, PendingIntent operation) {
|
||||||
|
setExact(type, triggerTime, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
|
||||||
|
setExact(type, triggerAtMillis, operation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,63 @@ import android.os.PersistableBundle;
|
|||||||
|
|
||||||
public class JobInfo {
|
public class JobInfo {
|
||||||
|
|
||||||
|
private ComponentName service;
|
||||||
|
long initialBackoffMillis;
|
||||||
|
int backoffPolicy;
|
||||||
|
private PersistableBundle extras;
|
||||||
|
long periodicMillis;
|
||||||
|
private int id;
|
||||||
|
boolean running;
|
||||||
|
long minLatencyMillis;
|
||||||
|
|
||||||
public JobInfo() {}
|
public JobInfo() {}
|
||||||
|
|
||||||
|
public ComponentName getService() {
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PersistableBundle getExtras() {
|
||||||
|
return extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "JobInfo{"
|
||||||
|
+ "jobService=" + service
|
||||||
|
+ ", initialBackoffMillis=" + initialBackoffMillis
|
||||||
|
+ ", backoffPolicy=" + backoffPolicy
|
||||||
|
+ ", extras=" + extras
|
||||||
|
+ ", periodicMillis=" + periodicMillis
|
||||||
|
+ ", id=" + id
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
public Builder(int jobId, ComponentName jobService) {}
|
|
||||||
|
private JobInfo jobInfo;
|
||||||
|
|
||||||
|
public Builder(int jobId, ComponentName jobService) {
|
||||||
|
jobInfo = new JobInfo();
|
||||||
|
jobInfo.id = jobId;
|
||||||
|
jobInfo.service = jobService;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
|
public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
|
||||||
|
jobInfo.initialBackoffMillis = initialBackoffMillis;
|
||||||
|
jobInfo.backoffPolicy = backoffPolicy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setExtras(PersistableBundle extras) {
|
public Builder setExtras(PersistableBundle extras) {
|
||||||
|
jobInfo.extras = extras;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setMinimumLatency(long minLatencyMillis) {
|
public Builder setMinimumLatency(long minLatencyMillis) {
|
||||||
|
jobInfo.minLatencyMillis = minLatencyMillis;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +70,7 @@ public class JobInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Builder setPeriodic(long dummy) {
|
public Builder setPeriodic(long dummy) {
|
||||||
|
jobInfo.periodicMillis = dummy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +99,7 @@ public class JobInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public JobInfo build() {
|
public JobInfo build() {
|
||||||
return new JobInfo();
|
return jobInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/api-impl/android/app/job/JobParameters.java
Normal file
16
src/api-impl/android/app/job/JobParameters.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package android.app.job;
|
||||||
|
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
|
||||||
|
public class JobParameters {
|
||||||
|
|
||||||
|
JobInfo jobInfo;
|
||||||
|
|
||||||
|
JobParameters(JobInfo jobInfo) {
|
||||||
|
this.jobInfo = jobInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PersistableBundle getExtras() {
|
||||||
|
return jobInfo.getExtras();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
package android.app.job;
|
package android.app.job;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
public class JobScheduler {
|
public class JobScheduler {
|
||||||
|
private static final String TAG = "JobScheduler";
|
||||||
|
|
||||||
|
static Map<Integer,JobInfo> pendingJobs = new HashMap<>();
|
||||||
|
private static Map<Class<? extends JobService>, JobService> runningServices = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all jobs that have been scheduled by the calling application.
|
* Retrieve all jobs that have been scheduled by the calling application.
|
||||||
*
|
*
|
||||||
@@ -11,7 +23,7 @@ public class JobScheduler {
|
|||||||
* currently started as well as those that are still waiting to run.
|
* currently started as well as those that are still waiting to run.
|
||||||
*/
|
*/
|
||||||
public List<JobInfo> getAllPendingJobs() {
|
public List<JobInfo> getAllPendingJobs() {
|
||||||
return new ArrayList<JobInfo>();
|
return new ArrayList<>(pendingJobs.values());
|
||||||
};
|
};
|
||||||
|
|
||||||
public int enqueue(JobInfo job, JobWorkItem work) {
|
public int enqueue(JobInfo job, JobWorkItem work) {
|
||||||
@@ -19,9 +31,47 @@ public class JobScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int schedule(JobInfo job) {
|
public int schedule(JobInfo job) {
|
||||||
|
Slog.i(TAG, "JobScheduler.schedule() called with job: " + job);
|
||||||
|
if (pendingJobs.containsKey(job.getId()))
|
||||||
|
return 1; //RESULT_SUCCESS
|
||||||
|
pendingJobs.put(job.getId(), job);
|
||||||
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
String className = job.getService().getClassName();
|
||||||
|
Class <? extends JobService> cls = Class.forName(className).asSubclass(JobService.class);
|
||||||
|
if (!runningServices.containsKey(cls)) {
|
||||||
|
JobService service = cls.getConstructor().newInstance();
|
||||||
|
service.attachBaseContext(new Context());
|
||||||
|
service.onCreate();
|
||||||
|
runningServices.put(cls, service);
|
||||||
|
}
|
||||||
|
job.running = true;
|
||||||
|
boolean result = runningServices.get(cls).onStartJob(new JobParameters(job));
|
||||||
|
Slog.i(TAG, "onStartJob() returned " + result);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, job.minLatencyMillis);
|
||||||
return 1; //RESULT_SUCCESS
|
return 1; //RESULT_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel(int dummy) {
|
public void cancel(int id) {
|
||||||
|
JobInfo job = pendingJobs.remove(id);
|
||||||
|
if (job != null && job.running) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
JobService service = runningServices.get(job.getService().getClass());
|
||||||
|
if (service != null) {
|
||||||
|
JobParameters params = new JobParameters(job);
|
||||||
|
service.onStopJob(params);
|
||||||
|
job.running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,31 @@
|
|||||||
package android.app.job;
|
package android.app.job;
|
||||||
|
|
||||||
public class JobService {
|
import android.app.Service;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
public abstract class JobService extends Service {
|
||||||
|
private static final String TAG = "JobService";
|
||||||
|
|
||||||
|
public abstract boolean onStartJob(JobParameters params);
|
||||||
|
|
||||||
|
public abstract boolean onStopJob(JobParameters params);
|
||||||
|
|
||||||
|
public void jobFinished(JobParameters params, boolean needsReschedule) {
|
||||||
|
Slog.i(TAG, "jobFinished(" + params + ", " + needsReschedule + ") called");
|
||||||
|
params.jobInfo.running = false;
|
||||||
|
if (needsReschedule || params.jobInfo.periodicMillis != 0) {
|
||||||
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
params.jobInfo.running = true;
|
||||||
|
boolean result = onStartJob(params);
|
||||||
|
Slog.i(TAG, "onStartJob() returned " + result);
|
||||||
|
}
|
||||||
|
}, needsReschedule ? params.jobInfo.initialBackoffMillis : params.jobInfo.periodicMillis);
|
||||||
|
} else {
|
||||||
|
JobScheduler.pendingJobs.remove(params.jobInfo.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class Intent implements Parcelable {
|
|||||||
private int flags;
|
private int flags;
|
||||||
private String type;
|
private String type;
|
||||||
private String packageName;
|
private String packageName;
|
||||||
|
private Intent selector;
|
||||||
|
|
||||||
public Intent() {}
|
public Intent() {}
|
||||||
public Intent(Intent o) {
|
public Intent(Intent o) {
|
||||||
@@ -402,11 +403,17 @@ public class Intent implements Parcelable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelector(Intent selector) {}
|
public void setSelector(Intent selector) {
|
||||||
|
this.selector = selector;
|
||||||
|
}
|
||||||
|
|
||||||
public void setClipData(ClipData clip) {}
|
public void setClipData(ClipData clip) {}
|
||||||
|
|
||||||
public String resolveType(Context context) {
|
public String resolveType(Context context) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Intent getSelector() {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
package android.os;
|
package android.os;
|
||||||
|
|
||||||
public class PersistableBundle extends BaseBundle {
|
public class PersistableBundle extends BaseBundle {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String toString() {
|
||||||
|
return "PersistableBundle[" + mMap.toString() + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,13 +94,13 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
|||||||
@Override
|
@Override
|
||||||
public boolean engineIsKeyEntry(String alias) {
|
public boolean engineIsKeyEntry(String alias) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'engineIsKeyEntry'");
|
return map.containsKey(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean engineIsCertificateEntry(String alias) {
|
public boolean engineIsCertificateEntry(String alias) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'engineIsCertificateEntry'");
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2221,4 +2221,6 @@ public class View implements Drawable.Callback {
|
|||||||
public WindowInsets computeSystemWindowInsets(WindowInsets insets, Rect contentInsets) { return insets; }
|
public WindowInsets computeSystemWindowInsets(WindowInsets insets, Rect contentInsets) { return insets; }
|
||||||
|
|
||||||
public boolean isDuplicateParentStateEnabled() { return false; }
|
public boolean isDuplicateParentStateEnabled() { return false; }
|
||||||
|
|
||||||
|
public void setBackgroundTintMode(PorterDuff.Mode tintMode) {}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/api-impl/android/widget/TimePicker.java
Normal file
17
src/api-impl/android/widget/TimePicker.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package android.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class TimePicker extends View {
|
||||||
|
|
||||||
|
public TimePicker(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimePicker(Context context, AttributeSet attributeSet) {
|
||||||
|
super(context, attributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -64,6 +64,7 @@ srcs = [
|
|||||||
'android/app/backup/BackupAgentHelper.java',
|
'android/app/backup/BackupAgentHelper.java',
|
||||||
'android/app/backup/BackupManager.java',
|
'android/app/backup/BackupManager.java',
|
||||||
'android/app/job/JobInfo.java',
|
'android/app/job/JobInfo.java',
|
||||||
|
'android/app/job/JobParameters.java',
|
||||||
'android/app/job/JobScheduler.java',
|
'android/app/job/JobScheduler.java',
|
||||||
'android/app/job/JobService.java',
|
'android/app/job/JobService.java',
|
||||||
'android/app/job/JobWorkItem.java',
|
'android/app/job/JobWorkItem.java',
|
||||||
@@ -644,6 +645,7 @@ srcs = [
|
|||||||
'android/widget/TableRow.java',
|
'android/widget/TableRow.java',
|
||||||
'android/widget/TextSwitcher.java',
|
'android/widget/TextSwitcher.java',
|
||||||
'android/widget/TextView.java',
|
'android/widget/TextView.java',
|
||||||
|
'android/widget/TimePicker.java',
|
||||||
'android/widget/Toast.java',
|
'android/widget/Toast.java',
|
||||||
'android/widget/ToggleButton.java',
|
'android/widget/ToggleButton.java',
|
||||||
'android/widget/Toolbar.java',
|
'android/widget/Toolbar.java',
|
||||||
|
|||||||
Reference in New Issue
Block a user