1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.development; 18 19 import android.app.Notification; 20 import android.app.NotificationChannel; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.app.Service; 24 import android.content.Intent; 25 import android.os.IBinder; 26 import android.os.UserHandle; 27 import android.provider.Settings; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.Nullable; 31 32 import com.android.settings.R; 33 34 public class PageAgnosticNotificationService extends Service { 35 36 private static final String NOTIFICATION_CHANNEL_ID = 37 "com.android.settings.development.PageAgnosticNotificationService"; 38 public static final String INTENT_ACTION_DISMISSED = 39 "com.android.settings.development.NOTIFICATION_DISMISSED"; 40 41 // Updating the notification ID to avoid the notification being dismissed 42 // accidentally by other notifications. ID used is the bug id where this was 43 // reported. 44 private static final int NOTIFICATION_ID = 388678898; 45 46 static final int DISABLE_UPDATES_SETTING = 1; 47 48 private NotificationManager mNotificationManager; 49 50 @Nullable 51 @Override onBind(@onNull Intent intent)52 public IBinder onBind(@NonNull Intent intent) { 53 return null; 54 } 55 56 // create a notification channel to post persistent notification createNotificationChannel()57 private void createNotificationChannel() { 58 NotificationChannel channel = 59 new NotificationChannel( 60 NOTIFICATION_CHANNEL_ID, 61 getString(R.string.page_agnostic_notification_channel_name), 62 NotificationManager.IMPORTANCE_HIGH); 63 mNotificationManager = getSystemService(NotificationManager.class); 64 if (mNotificationManager != null) { 65 mNotificationManager.createNotificationChannel(channel); 66 } 67 } 68 69 @Override onCreate()70 public void onCreate() { 71 super.onCreate(); 72 createNotificationChannel(); 73 74 // No updates should be allowed in page-agnostic mode 75 disableAutomaticUpdates(); 76 } 77 buildNotification()78 private Notification buildNotification() { 79 // Get the title and text according to page size 80 boolean isIn16kbMode = Enable16kUtils.isUsing16kbPages(); 81 String title = 82 isIn16kbMode 83 ? getString(R.string.page_agnostic_16k_pages_title) 84 : getString(R.string.page_agnostic_4k_pages_title); 85 String text = 86 isIn16kbMode 87 ? getString(R.string.page_agnostic_16k_pages_text_short) 88 : getString(R.string.page_agnostic_4k_pages_text_short); 89 90 Intent notifyIntent = new Intent(this, PageAgnosticWarningActivity.class); 91 // Set the Activity to start in a new, empty task. 92 notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 93 94 // Create the PendingIntent. 95 PendingIntent notifyPendingIntent = 96 PendingIntent.getActivity( 97 this, 98 0, 99 notifyIntent, 100 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 101 102 Intent dismissIntent = new Intent(this, Enable16KBootReceiver.class); 103 dismissIntent.setAction(INTENT_ACTION_DISMISSED); 104 PendingIntent dismissPendingIntent = 105 PendingIntent.getBroadcast( 106 this.getApplicationContext(), 107 0, 108 dismissIntent, 109 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 110 111 Notification.Action action = 112 new Notification.Action.Builder( 113 R.drawable.empty_icon, 114 getString(R.string.page_agnostic_notification_action), 115 notifyPendingIntent) 116 .build(); 117 118 // TODO:(b/349860833) Change text style to BigTextStyle once the ellipsis issue is fixed. 119 Notification.Builder builder = 120 new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) 121 .setContentTitle(title) 122 .setContentText(text) 123 .setOngoing(true) 124 .setSmallIcon(R.drawable.ic_settings_24dp) 125 .setContentIntent(notifyPendingIntent) 126 .setDeleteIntent(dismissPendingIntent) 127 .addAction(action); 128 129 return builder.build(); 130 } 131 disableAutomaticUpdates()132 private void disableAutomaticUpdates() { 133 final int currentState = 134 Settings.Global.getInt( 135 getApplicationContext().getContentResolver(), 136 Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 137 0 /* default */); 138 // 0 means enabled, 1 means disabled 139 if (currentState == 0) { 140 // automatic updates are enabled, disable them 141 Settings.Global.putInt( 142 getApplicationContext().getContentResolver(), 143 Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 144 DISABLE_UPDATES_SETTING); 145 } 146 } 147 148 @Override onStartCommand(@ullable Intent intent, int flags, int startId)149 public int onStartCommand(@Nullable Intent intent, int flags, int startId) { 150 Notification notification = buildNotification(); 151 if (mNotificationManager != null) { 152 mNotificationManager.notifyAsUser(null, NOTIFICATION_ID, notification, 153 UserHandle.ALL); 154 } 155 return Service.START_REDELIVER_INTENT; 156 } 157 } 158