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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -14,6 +16,13 @@ public class ActivityManager {
|
||||
|
||||
public static class RunningAppProcessInfo{
|
||||
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 {
|
||||
@@ -21,7 +30,7 @@ public class ActivityManager {
|
||||
}
|
||||
|
||||
public List<RunningAppProcessInfo> getRunningAppProcesses() {
|
||||
return null;
|
||||
return Arrays.asList(new RunningAppProcessInfo(Process.myPid(), Context.this_application.getPackageName()));
|
||||
}
|
||||
|
||||
public boolean isLowRamDevice() {return false;}
|
||||
|
||||
@@ -1,13 +1,51 @@
|
||||
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 void cancel(PendingIntent operation) {}
|
||||
private static final String TAG = "AlarmManager";
|
||||
|
||||
public void setInexactRepeating(int type, long triggerTime, long interval, PendingIntent operation) {}
|
||||
|
||||
public void setExact(int type, long triggerTime, PendingIntent operation) {}
|
||||
|
||||
public void set(int type, long triggerTime, PendingIntent operation) {}
|
||||
|
||||
public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {}
|
||||
public void cancel(PendingIntent operation) {
|
||||
Slog.i(TAG, "cancel(" + operation + ") called");
|
||||
}
|
||||
|
||||
public void setInexactRepeating(int type, long triggerTime, long interval, PendingIntent operation) {
|
||||
Slog.i(TAG, "setInexactRepeating(" + type + ", " + triggerTime + ", " + interval + ", " + operation + ") called");
|
||||
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 {
|
||||
|
||||
private ComponentName service;
|
||||
long initialBackoffMillis;
|
||||
int backoffPolicy;
|
||||
private PersistableBundle extras;
|
||||
long periodicMillis;
|
||||
private int id;
|
||||
boolean running;
|
||||
long minLatencyMillis;
|
||||
|
||||
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 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) {
|
||||
jobInfo.initialBackoffMillis = initialBackoffMillis;
|
||||
jobInfo.backoffPolicy = backoffPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setExtras(PersistableBundle extras) {
|
||||
jobInfo.extras = extras;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinimumLatency(long minLatencyMillis) {
|
||||
jobInfo.minLatencyMillis = minLatencyMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -27,6 +70,7 @@ public class JobInfo {
|
||||
}
|
||||
|
||||
public Builder setPeriodic(long dummy) {
|
||||
jobInfo.periodicMillis = dummy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -55,7 +99,7 @@ public class JobInfo {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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 {
|
||||
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.
|
||||
*
|
||||
@@ -11,7 +23,7 @@ public class JobScheduler {
|
||||
* currently started as well as those that are still waiting to run.
|
||||
*/
|
||||
public List<JobInfo> getAllPendingJobs() {
|
||||
return new ArrayList<JobInfo>();
|
||||
return new ArrayList<>(pendingJobs.values());
|
||||
};
|
||||
|
||||
public int enqueue(JobInfo job, JobWorkItem work) {
|
||||
@@ -19,9 +31,47 @@ public class JobScheduler {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 String type;
|
||||
private String packageName;
|
||||
private Intent selector;
|
||||
|
||||
public Intent() {}
|
||||
public Intent(Intent o) {
|
||||
@@ -402,11 +403,17 @@ public class Intent implements Parcelable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setSelector(Intent selector) {}
|
||||
public void setSelector(Intent selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public void setClipData(ClipData clip) {}
|
||||
|
||||
public String resolveType(Context context) {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Intent getSelector() {
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
package android.os;
|
||||
|
||||
public class PersistableBundle extends BaseBundle {
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return "PersistableBundle[" + mMap.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,13 +94,13 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
||||
@Override
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'engineIsKeyEntry'");
|
||||
return map.containsKey(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'engineIsCertificateEntry'");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2221,4 +2221,6 @@ public class View implements Drawable.Callback {
|
||||
public WindowInsets computeSystemWindowInsets(WindowInsets insets, Rect contentInsets) { return insets; }
|
||||
|
||||
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/BackupManager.java',
|
||||
'android/app/job/JobInfo.java',
|
||||
'android/app/job/JobParameters.java',
|
||||
'android/app/job/JobScheduler.java',
|
||||
'android/app/job/JobService.java',
|
||||
'android/app/job/JobWorkItem.java',
|
||||
@@ -644,6 +645,7 @@ srcs = [
|
||||
'android/widget/TableRow.java',
|
||||
'android/widget/TextSwitcher.java',
|
||||
'android/widget/TextView.java',
|
||||
'android/widget/TimePicker.java',
|
||||
'android/widget/Toast.java',
|
||||
'android/widget/ToggleButton.java',
|
||||
'android/widget/Toolbar.java',
|
||||
|
||||
Reference in New Issue
Block a user