Alarm Manager policy TARE page implementation

An alarm manager policy page is needed in the TARE developer option
settings to allow developers to both view and edit the current values of
all the factors under the alarm manager policy. The page uses a dropdown
so that the user can easily switch between the different policies. For
the factors with subfactors, the user simply clicks on the factor and
the subfactors will pop up under it.

Bug: 191876714
Bug: 191876567

Test: Manual (open Settings > System > Developer Options > TARE > Alarm
Manger and verify all factors are there)

Change-Id: Ie036e26df80947d23041bedfd5b1385e48069b6b
This commit is contained in:
alinasuarez
2021-07-30 20:25:19 +00:00
parent 2cad599ca6
commit aef6ac2889
9 changed files with 435 additions and 12 deletions

View File

@@ -1485,6 +1485,9 @@
android:label="@string/tare_settings" android:label="@string/tare_settings"
android:exported="false" /> android:exported="false" />
<activity android:name=".development.tare.DropdownActivity"
android:exported="false" />
<activity android:name="SetFullBackupPassword" <activity android:name="SetFullBackupPassword"
android:label="@string/local_backup_password_title" android:label="@string/local_backup_password_title"
android:exported="false" /> android:exported="false" />

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/factor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:paddingLeft="35dp" />
<TextView
android:id="@+id/factor_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:paddingLeft="35dp" />
</LinearLayout>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".development.tare.DropdownActivity">
<com.android.settingslib.widget.settingsspinner.SettingsSpinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:theme="@style/Widget.PopupWindow.Settings"
android:padding="10dp" />
<FrameLayout
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/spinner"
app:layout_constraintVertical_bias="0" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -18,7 +18,6 @@
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -36,6 +35,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="20dp" android:padding="20dp"
android:clickable="true" android:clickable="true"
android:onClick="launchAlarmManagerPage"
android:text="@string/tare_alarmmanager" android:text="@string/tare_alarmmanager"
android:textColor="?android:attr/textColorSecondary" /> android:textColor="?android:attr/textColorSecondary" />

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
<ExpandableListView
android:id="@+id/factor_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -13629,7 +13629,125 @@
<!-- Allows user to view JobScheduler policy factors. JobScheduler is the name of an Android <!-- Allows user to view JobScheduler policy factors. JobScheduler is the name of an Android
system service and cannot be translated.[CHAR LIMIT=40]--> system service and cannot be translated.[CHAR LIMIT=40]-->
<string name="tare_jobscheduler" translatable="false">JobScheduler</string> <string name="tare_jobscheduler" translatable="false">JobScheduler</string>
<!-- Toast notifying the developer that settings were reverted to their <!-- Toast notifying the developer that settings were reverted to their default values in
default [CHAR LIMIT=40]--> TARE [CHAR LIMIT=40]-->
<string name="tare_settings_reverted_toast">Settings reverted to default.</string> <string name="tare_settings_reverted_toast">Settings reverted to default.</string>
<!-- Title for the TARE policy factor that determines the maximum credits an app can have in one
battery life cycle. Satiated means battery is fully charged; If this is not easily translatable,
translate "maximum balance when device is fully charged" instead. [CHAR LIMIT=40]-->
<string name="tare_max_satiated_balance">Maximum Satiated Balance</string>
<!-- Title for the TARE policy factor that determines the maximum credits in circulation between
all the apps [CHAR LIMIT=40]-->
<string name="tare_max_circulation">Maximum Circulation</string>
<!-- Title for the TARE policy factor that determines the minimum credits an app can have in one
battery life cycle. Satiated means battery is fully charged; If this is not easily translatable,
translate "minimum balance when device is fully charged" instead. [CHAR LIMIT=40]-->
<string name="tare_min_satiated_balance">Minimum Satiated Balance</string>
<!-- Title for the various modifiers that alter the cost of TARE tasks based on battery status
(charging, power save mode, etc.) [CHAR LIMIT=40]-->
<string name="tare_modifiers">Modifiers</string>
<!-- Title for the various TARE policy's action's cost to produce and price paid by
apps [CHAR LIMIT=40]-->
<string name="tare_actions">Actions</string>
<!-- Title for the instant, ongoing, and max rewards apps can obtain for different actions that
benefit the user. [CHAR LIMIT=40]-->
<string name="tare_rewards">Rewards</string>
<!-- Title for the Allow While Idle Exact Wakeup Alarm set via
AlarmManager.setExactAndAllowWhileIdle() [CHAR LIMIT=40]-->
<string name="tare_wakeup_exact_idle" translatable="false">
Allow While Idle Exact Wakeup Alarm</string>
<!-- Title for the Allow While Idle Inexact Wakeup Alarm set via
AlarmManager.setAndAllowWhileIdle() [CHAR LIMIT=40]-->
<string name="tare_wakeup_inexact_idle" translatable="false">
Allow While Idle Inexact Wakeup Alarm</string>
<!-- Title for the Exact Wakeup Alarm set via AlarmManager.setExact() [CHAR LIMIT=40]-->
<string name="tare_wakeup_exact" translatable="false">Exact Wakeup Alarm</string>
<!-- Title for the Inexact Wakeup Alarm set via AlarmManager.set() [CHAR LIMIT=40]-->
<string name="tare_wakeup_inexact" translatable="false">Inexact Wakeup Alarm</string>
<!-- Title for the Allow While Idle Exact NonWakeup Alarm set via
AlarmManager.setExactAndAllowWhileIdle() [CHAR LIMIT=40]-->
<string name="tare_nonwakeup_exact_idle" translatable="false">
Allow While Idle Exact NonWakeup Alarm</string>
<!-- Title for the Exact NonWakeup Alarm set via AlarmManager.setExact() [CHAR LIMIT=40]-->
<string name="tare_nonwakeup_exact" translatable="false">Exact NonWakeup Alarm</string>
<!-- Title for the Allow While Idle Inexact NonWakeup Alarm set via
AlarmManager.setAndAllowWhileIdle() [CHAR LIMIT=40]-->
<string name="tare_nonwakeup_inexact_idle" translatable="false">
Allow While Idle Inexact NonWakeup Alarm</string>
<!-- Title for the Inexact NonWakeup Alarm set via AlarmManager.set() [CHAR LIMIT=40]-->
<string name="tare_nonwakeup_inexact" translatable="false">Inexact NonWakeup Alarm</string>
<!-- Title for the AlarmClock alarm set via AlarmManager.setAlarmClock() [CHAR LIMIT=40]-->
<string name="tare_alarm_clock" translatable="false">AlarmClock</string>
<!-- Exempted apps are those apps exempted from most power saving features. [CHAR LIMIT=40]-->
<string name="tare_exempted">Exempted</string>
<!-- A headless system app is a preinstalled app that does not have any activities/UI that the
user can interact with. [CHAR LIMIT=40]-->
<string name="tare_headless_app">Headless System App</string>
<!-- Other apps are those apps interacted with by users that are not exempted or headless
system apps. [CHAR LIMIT=40]-->
<string name="tare_other_app">Other App</string>
<!-- Top activity means an app is in the TOP android process state and is thus visible to the
user[CHAR LIMIT=40]-->
<string name="tare_top_activity">Top Activity</string>
<!-- An event type denoting that a notification was viewed by the user, as defined in
UsageEvents.java [CHAR LIMIT=40]-->
<string name="tare_notification_seen">Notification Seen</string>
<!-- An event type denoting that a notification was viewed by the user within 15 minutes
[CHAR LIMIT=40]-->
<string name="tare_notification_seen_15_min">Notification Seen Within 15 Minutes</string>
<!-- An event type denoting that a notification was interacted with in some way by the user
[CHAR LIMIT=40]-->
<string name="tare_notification_interaction">Notification Interaction</string>
<!-- An event type denoting that an app's widget was interacted with in some way by the user
[CHAR LIMIT=40]-->
<string name="tare_widget_interaction">Widget Interaction</string>
<!-- An event type denoting that an app was interacted with in some way by the user
[CHAR LIMIT=40]-->
<string name="tare_other_interaction">Other User Interaction</string>
<!-- Titles for the minimum satiated credit balances for different types of apps
(per battery cycle). Satiated means battery is fully charged. [CHAR LIMIT=40]-->
<string-array name="tare_min_satiated_balance_subfactors" translatable="false">
<item>@string/tare_exempted</item>
<item>@string/tare_headless_app</item>
<item>@string/tare_other_app</item>
</string-array>
<!-- Various modifier subfactors that alter the cost of TARE tasks depending on what battery
state the device is in [CHAR LIMIT=40]-->
<string-array name="tare_modifiers_subfactors">
<item>Charging</item>
<!-- Doze refers to the Android Doze feature -->
<item>Doze</item>
<item>Power Save Mode</item>
<!-- An app's process state is the internal level of an app's process inside the system -->
<item>Process State</item>
</string-array>
<!-- Various AlarmManager alarms with different costs to produce and price paid by apps
if they want to produce these alarms. Alarm in this context refers to the possible alarm cases
in AlarmManager. [CHAR LIMIT=40]-->
<string-array name="tare_actions_subfactors" translatable="false">
<item>@string/tare_wakeup_exact_idle</item>
<item>@string/tare_wakeup_inexact_idle</item>
<item>@string/tare_wakeup_exact</item>
<item>@string/tare_wakeup_inexact</item>
<item>@string/tare_nonwakeup_exact_idle</item>
<item>@string/tare_nonwakeup_exact</item>
<item>@string/tare_nonwakeup_inexact_idle</item>
<item>@string/tare_nonwakeup_inexact</item>
<item>@string/tare_alarm_clock</item>
</string-array>
<!-- Titles for the different rewards apps could obtain for actions that benefit the user;
each has instant, ongoing, and max credit rewards apps could gain [CHAR LIMIT=40]-->
<string-array name="tare_rewards_subfactors" translatable="false">
<item>@string/tare_top_activity</item>
<item>@string/tare_notification_seen</item>
<item>@string/tare_notification_seen_15_min</item>
<item>@string/tare_notification_interaction</item>
<item>@string/tare_widget_interaction</item>
<item>@string/tare_other_interaction</item>
</string-array>
<!-- Array used to populate dropdown menu with the different policies in the TARE
settings [CHAR LIMIT=40]-->
<string-array name="tare_policies" translatable="false">
<item>@string/tare_alarmmanager</item>
</string-array>
</resources> </resources>

View File

@@ -0,0 +1,162 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development.tare;
import android.app.Fragment;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.TextView;
import android.widget.Toast;
import com.android.settings.R;
/**
* Creates the AlarmManager fragment to display all the AlarmManager factors
* when the AlarmManager policy is chosen in the dropdown TARE menu.
*/
public class AlarmManagerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.tare_policy_fragment, null);
ExpandableListView elv = (ExpandableListView) v.findViewById(R.id.factor_list);
final SavedTabsListAdapter expListAdapter = new SavedTabsListAdapter();
elv.setGroupIndicator(null);
elv.setAdapter(expListAdapter);
elv.setOnChildClickListener(new OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
final String selected =
(String) expListAdapter.getChild(groupPosition, childPosition);
Toast.makeText(getActivity(), selected, Toast.LENGTH_SHORT).show();
return true;
}
});
return v;
}
/**
* Creates the expandable list containing all AlarmManager factors within the
* AlarmManager fragment.
*/
public class SavedTabsListAdapter extends BaseExpandableListAdapter {
private final LayoutInflater mInflater;
private Resources mResources = getActivity().getResources();
private String[] mGroups = {
mResources.getString(R.string.tare_max_circulation),
mResources.getString(R.string.tare_max_satiated_balance),
mResources.getString(R.string.tare_min_satiated_balance),
mResources.getString(R.string.tare_modifiers),
mResources.getString(R.string.tare_actions),
mResources.getString(R.string.tare_rewards)
};
/*
* First two are empty arrays because the first two factors have no subfactors (no
* children).
*/
private String[][] mChildren = {
{},
{},
mResources.getStringArray(R.array.tare_min_satiated_balance_subfactors),
mResources.getStringArray(R.array.tare_modifiers_subfactors),
mResources.getStringArray(R.array.tare_actions_subfactors),
mResources.getStringArray(R.array.tare_rewards_subfactors)
};
public SavedTabsListAdapter() {
mInflater = LayoutInflater.from(getActivity());
}
@Override
public int getGroupCount() {
return mGroups.length;
}
@Override
public int getChildrenCount(int groupPosition) {
return mChildren[groupPosition].length;
}
@Override
public Object getGroup(int groupPosition) {
return mGroups[groupPosition];
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mChildren[groupPosition][childPosition];
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
}
TextView factor = (TextView) convertView.findViewById(android.R.id.text1);
factor.setText(getGroup(groupPosition).toString());
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
// Here a custom child item is used instead of android.R.simple_list_item_2 because it
// is more customizable for this specific UI
if (convertView == null) {
convertView = mInflater.inflate(R.layout.tare_child_item, null);
}
TextView factor = (TextView) convertView.findViewById(R.id.factor);
TextView value = (TextView) convertView.findViewById(R.id.factor_number);
// TODO: Replace these hardcoded values with either default or user inputted TARE values
factor.setText(getChild(groupPosition, childPosition).toString());
value.setText("500");
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development.tare;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.android.settings.R;
/**
* Dropdown activity to allow for the user to easily switch between the different TARE
* policies in the developer options of settings. Depending on what is chosen, the fragment
* containing that specific policies' factors will be generated.
*/
public class DropdownActivity extends Activity {
private Fragment mAlarmManagerFragment;
private Spinner mSpinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tare_dropdown_page);
mSpinner = findViewById(R.id.spinner);
mAlarmManagerFragment = new AlarmManagerFragment();
String[] policies = getResources().getStringArray(R.array.tare_policies);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(DropdownActivity.this,
android.R.layout.simple_list_item_1, policies);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinner.setAdapter(arrayAdapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position,
long id) {
openFragment(mAlarmManagerFragment);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
/** Selects the correct policy fragment to display */
private void openFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.commit();
}
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.development.tare; package com.android.settings.development.tare;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
@@ -57,9 +58,14 @@ public class TareHomePage extends Activity {
}); });
} }
/** This method should revert the TARE settings to the original default settings */ /** Reverts the TARE settings to the original default settings */
// TODO: Establish default TARE values and make this method revert all settings back to default // TODO: Establish default TARE values and make this method revert all settings back to default.
public void revertSettings(View v) { public void revertSettings(View v) {
Toast.makeText(this, R.string.tare_settings_reverted_toast, Toast.LENGTH_LONG).show(); Toast.makeText(this, R.string.tare_settings_reverted_toast, Toast.LENGTH_LONG).show();
} }
/** Opens up the AlarmManager TARE policy page with its factors to view and edit */
public void launchAlarmManagerPage(View v) {
startActivity(new Intent(getApplicationContext(), DropdownActivity.class));
}
} }