-
Notifications
You must be signed in to change notification settings - Fork 1
Temporary build: Quest KeepAwake APK #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2999056
c885e1c
b1b443e
31b145d
405a484
e095156
68440f2
1e1086e
c6d314d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| name: Temp Quest KeepAwake APK | ||
| on: | ||
| pull_request: | ||
| branches: [main] | ||
| paths: | ||
| - 'quest-keepawake-build/**' | ||
| - '.github/workflows/temp-quest-keepawake-build.yml' | ||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-java@v4 | ||
| with: | ||
| distribution: temurin | ||
| java-version: '17' | ||
| - uses: android-actions/setup-android@v3 | ||
| - uses: gradle/actions/setup-gradle@v4 | ||
| with: | ||
| gradle-version: '8.4' | ||
| - name: Install SDK 33 | ||
| run: sdkmanager 'platforms;android-33' 'build-tools;33.0.2' | ||
| - name: Build debug APK | ||
| run: gradle -p quest-keepawake-build assembleDebug --stacktrace | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: QuestNavKeepAwake-always-on-debug | ||
| path: quest-keepawake-build/app/build/outputs/apk/debug/app-debug.apk | ||
| if-no-files-found: error |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| plugins { id 'com.android.application' } | ||
| android { | ||
| namespace 'com.questnav.keepawake' | ||
| compileSdk 33 | ||
| defaultConfig { applicationId 'com.questnav.keepawake'; minSdk 29; targetSdk 32; versionCode 2; versionName '1.1-always-on' } | ||
| buildTypes { release { minifyEnabled false }; debug { minifyEnabled false } } | ||
| compileOptions { sourceCompatibility JavaVersion.VERSION_17; targetCompatibility JavaVersion.VERSION_17 } | ||
| lint { abortOnError false } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <uses-permission android:name="android.permission.WAKE_LOCK" /> | ||
| <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | ||
| <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||
| <uses-permission android:name="android.permission.WRITE_SETTINGS" /> | ||
| <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> | ||
| <application android:label="Quest KeepAwake" android:theme="@android:style/Theme.DeviceDefault"> | ||
| <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop"> | ||
| <intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter> | ||
| </activity> | ||
| <receiver android:name=".BootReceiver" android:exported="true" android:directBootAware="true"> | ||
| <intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/><action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/></intent-filter> | ||
| </receiver> | ||
| <service android:name=".KeepAwakeService" android:exported="false" /> | ||
| </application> | ||
| </manifest> | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,3 @@ | ||||||||||||||||||||||||||||||||||||
| package com.questnav.keepawake; | ||||||||||||||||||||||||||||||||||||
| import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; | ||||||||||||||||||||||||||||||||||||
| public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent i){ c.startForegroundService(new Intent(c, KeepAwakeService.class)); } } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+2
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Android 12 (API 31) 以降では、バックグラウンドからフォアグラウンドサービスを開始する際、特定の条件下で
Suggested change
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package com.questnav.keepawake; | ||
| import android.app.*; import android.content.*; import android.os.*; import android.provider.Settings; import android.util.Log; | ||
| public class KeepAwakeService extends Service { | ||
| private static final String TAG="KeepAwakeService", CHANNEL_ID="keepawake_channel"; private static final long INTERVAL_MS=2000; | ||
| private final Handler handler=new Handler(Looper.getMainLooper()); private boolean running; private PowerManager.WakeLock wakeLock; | ||
| private final Runnable keepAwakeRunnable=new Runnable(){ @Override public void run(){ if(!running)return; sendProxClose(); handler.postDelayed(this,INTERVAL_MS); }}; | ||
| @Override public void onCreate(){ super.onCreate(); } | ||
| @Override public int onStartCommand(Intent intent,int flags,int startId){ if(running)return START_STICKY; running=true; createChannel(); startForeground(1,new Notification.Builder(this,CHANNEL_ID).setContentTitle("Quest KeepAwake").setContentText("Always-on keep-awake is active").setSmallIcon(android.R.drawable.ic_lock_idle_lock).setOngoing(true).build()); PowerManager pm=(PowerManager)getSystemService(POWER_SERVICE); wakeLock=pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"QuestNavKeepAwake::StayAwake"); wakeLock.acquire(); applySettings(); sendProxClose(); handler.postDelayed(keepAwakeRunnable,INTERVAL_MS); Log.i(TAG,"Always-on service started"); return START_STICKY; } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 防御的プログラミングの観点から、 @Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (running) return START_STICKY;
running = true;
createChannel();
startForeground(1, new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Quest KeepAwake")
.setContentText("Always-on keep-awake is active")
.setSmallIcon(android.R.drawable.ic_lock_idle_lock)
.setOngoing(true)
.build());
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (pm != null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "QuestNavKeepAwake::StayAwake");
wakeLock.acquire();
}
applySettings();
sendProxClose();
handler.postDelayed(keepAwakeRunnable, INTERVAL_MS);
Log.i(TAG, "Always-on service started");
return START_STICKY;
} |
||
| @Override public void onDestroy(){ running=false; handler.removeCallbacks(keepAwakeRunnable); if(wakeLock!=null&&wakeLock.isHeld())wakeLock.release(); super.onDestroy(); } | ||
| @Override public IBinder onBind(Intent intent){ return null; } | ||
| private void applySettings(){ ContentResolver cr=getContentResolver(); try{Settings.System.putInt(cr,Settings.System.SCREEN_OFF_TIMEOUT,Integer.MAX_VALUE);}catch(Exception e){Log.w(TAG,"screen timeout",e);} try{Settings.Global.putInt(cr,Settings.Global.STAY_ON_WHILE_PLUGGED_IN,3);}catch(Exception e){Log.w(TAG,"stay on",e);} try{Settings.Secure.putInt(cr,"adaptive_sleep",-1); Settings.Secure.putInt(cr,"sleep_timeout",-1); Settings.Secure.putInt(cr,"wake_gesture_enabled",0);}catch(Exception e){Log.w(TAG,"secure settings",e);} } | ||
| private void sendProxClose(){ try{Intent i=new Intent("com.oculus.vrpowermanager.prox_close"); i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); sendBroadcast(i); Log.d(TAG,"Sent prox_close");}catch(Exception e){Log.w(TAG,"prox_close",e);} } | ||
| private void createChannel(){ NotificationChannel c=new NotificationChannel(CHANNEL_ID,"KeepAwake Service",NotificationManager.IMPORTANCE_LOW); getSystemService(NotificationManager.class).createNotificationChannel(c); } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.questnav.keepawake; | ||
| import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.TextView; | ||
| public class MainActivity extends Activity { | ||
| @Override public void onCreate(Bundle b){ super.onCreate(b); startForegroundService(new Intent(this, KeepAwakeService.class)); TextView v=new TextView(this); v.setText("KeepAwake service is running.\nprox_close is sent every 2 seconds."); v.setTextSize(20); v.setPadding(32,32,32,32); setContentView(v); } | ||
|
Comment on lines
+2
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Android 6.0 (API 23) 以降では、
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle b) {
super.onCreate(b);
if (!Settings.System.canWrite(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
startForegroundService(new Intent(this, KeepAwakeService.class));
TextView v = new TextView(this);
v.setText("KeepAwake service is running.\\nprox_close is sent every 2 seconds.");
v.setTextSize(20);
v.setPadding(32, 32, 32, 32);
setContentView(v);
} |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| plugins { | ||
| id 'com.android.application' version '8.1.4' apply false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 | ||
| android.useAndroidX=true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| pluginManagement { repositories { google(); mavenCentral(); gradlePluginPortal() } } | ||
| dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS); repositories { google(); mavenCentral() } } | ||
| rootProject.name = 'QuestNavKeepAwake' | ||
| include ':app' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BootReceiverにandroid:directBootAware="true"が設定されており、デバイスの起動直後(ロック解除前)に送信されるLOCKED_BOOT_COMPLETEDを受信した際にKeepAwakeServiceを起動しようとします。しかし、起動対象の
KeepAwakeService自体にandroid:directBootAware="true"が設定されていないため、ロック解除前にサービスを起動しようとするとシステムによって起動が拒否されるか、正常に動作しません。デバイスの起動直後から確実にサービスを動作させるために、
KeepAwakeServiceにもandroid:directBootAware="true"を指定することをお勧めします。