1 /*
2  * Copyright (C) 2021 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.server.tare;
18 
19 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES;
20 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES;
21 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES;
22 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES;
23 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES;
24 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
25 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES;
26 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES;
27 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES;
28 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES;
29 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES;
30 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES;
31 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES;
32 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
33 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES;
34 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES;
35 import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES;
36 import static android.app.tare.EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES;
37 import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES;
38 import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES;
39 import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES;
40 import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
41 import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES;
42 import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
43 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
44 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
45 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
46 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES;
47 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES;
48 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES;
49 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES;
50 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES;
51 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES;
52 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES;
53 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES;
54 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES;
55 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES;
56 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES;
57 import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES;
58 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
59 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
60 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
61 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
62 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
63 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
64 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
65 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
66 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
67 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
68 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
69 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
70 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
71 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
72 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
73 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
74 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
75 import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
76 import static android.app.tare.EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT;
77 import static android.app.tare.EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT;
78 import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
79 import static android.app.tare.EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT;
80 import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED;
81 import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP;
82 import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
83 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
84 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
85 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
86 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
87 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_MAX;
88 import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
89 import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
90 import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX;
91 import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
92 import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT;
93 import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_MAX;
94 import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING;
95 import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
96 import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
97 import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
98 import static android.app.tare.EconomyManager.arcToCake;
99 import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
100 
101 import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
102 import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
103 import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
104 import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
105 import static com.android.server.tare.TareUtils.cakeToString;
106 
107 import android.annotation.NonNull;
108 import android.annotation.Nullable;
109 import android.content.ContentResolver;
110 import android.provider.DeviceConfig;
111 import android.util.IndentingPrintWriter;
112 import android.util.KeyValueListParser;
113 import android.util.Slog;
114 import android.util.SparseArray;
115 
116 /**
117  * Policy defining pricing information and daily ARC requirements and suggestions for
118  * AlarmManager.
119  */
120 public class AlarmManagerEconomicPolicy extends EconomicPolicy {
121     private static final String TAG = "TARE- " + AlarmManagerEconomicPolicy.class.getSimpleName();
122 
123     public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
124             TYPE_ACTION | POLICY_ALARM | 0;
125     public static final int ACTION_ALARM_WAKEUP_EXACT =
126             TYPE_ACTION | POLICY_ALARM | 1;
127     public static final int ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE =
128             TYPE_ACTION | POLICY_ALARM | 2;
129     public static final int ACTION_ALARM_WAKEUP_INEXACT =
130             TYPE_ACTION | POLICY_ALARM | 3;
131     public static final int ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE =
132             TYPE_ACTION | POLICY_ALARM | 4;
133     public static final int ACTION_ALARM_NONWAKEUP_EXACT =
134             TYPE_ACTION | POLICY_ALARM | 5;
135     public static final int ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE =
136             TYPE_ACTION | POLICY_ALARM | 6;
137     public static final int ACTION_ALARM_NONWAKEUP_INEXACT =
138             TYPE_ACTION | POLICY_ALARM | 7;
139     public static final int ACTION_ALARM_CLOCK =
140             TYPE_ACTION | POLICY_ALARM | 8;
141 
142     private static final int[] COST_MODIFIERS = new int[]{
143             COST_MODIFIER_CHARGING,
144             COST_MODIFIER_DEVICE_IDLE,
145             COST_MODIFIER_POWER_SAVE_MODE,
146             COST_MODIFIER_PROCESS_STATE
147     };
148 
149     private long mMinSatiatedBalanceExempted;
150     private long mMinSatiatedBalanceHeadlessSystemApp;
151     private long mMinSatiatedBalanceOther;
152     private long mMaxSatiatedBalance;
153     private long mInitialSatiatedConsumptionLimit;
154     private long mMinSatiatedConsumptionLimit;
155     private long mMaxSatiatedConsumptionLimit;
156 
157     private final KeyValueListParser mParser = new KeyValueListParser(',');
158     private final Injector mInjector;
159 
160     private final SparseArray<Action> mActions = new SparseArray<>();
161     private final SparseArray<Reward> mRewards = new SparseArray<>();
162 
AlarmManagerEconomicPolicy(InternalResourceService irs, Injector injector)163     AlarmManagerEconomicPolicy(InternalResourceService irs, Injector injector) {
164         super(irs);
165         mInjector = injector;
166         loadConstants("", null);
167     }
168 
169     @Override
setup(@onNull DeviceConfig.Properties properties)170     void setup(@NonNull DeviceConfig.Properties properties) {
171         super.setup(properties);
172         ContentResolver resolver = mIrs.getContext().getContentResolver();
173         loadConstants(mInjector.getSettingsGlobalString(resolver, TARE_ALARM_MANAGER_CONSTANTS),
174                 properties);
175     }
176 
177     @Override
getMinSatiatedBalance(final int userId, @NonNull final String pkgName)178     long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
179         if (mIrs.isPackageRestricted(userId, pkgName)) {
180             return 0;
181         }
182         if (mIrs.isPackageExempted(userId, pkgName)) {
183             return mMinSatiatedBalanceExempted;
184         }
185         if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
186             return mMinSatiatedBalanceHeadlessSystemApp;
187         }
188         // TODO: take other exemptions into account
189         return mMinSatiatedBalanceOther;
190     }
191 
192     @Override
getMaxSatiatedBalance(int userId, @NonNull String pkgName)193     long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
194         if (mIrs.isPackageRestricted(userId, pkgName)) {
195             return 0;
196         }
197         // TODO(230501287): adjust balance based on whether the app has the SCHEDULE_EXACT_ALARM
198         // permission granted. Apps without the permission granted shouldn't need a high balance
199         // since they won't be able to use exact alarms. Apps with the permission granted could
200         // have a higher balance, or perhaps just those with the USE_EXACT_ALARM permission since
201         // that is limited to specific use cases.
202         return mMaxSatiatedBalance;
203     }
204 
205     @Override
getInitialSatiatedConsumptionLimit()206     long getInitialSatiatedConsumptionLimit() {
207         return mInitialSatiatedConsumptionLimit;
208     }
209 
210     @Override
getMinSatiatedConsumptionLimit()211     long getMinSatiatedConsumptionLimit() {
212         return mMinSatiatedConsumptionLimit;
213     }
214 
215     @Override
getMaxSatiatedConsumptionLimit()216     long getMaxSatiatedConsumptionLimit() {
217         return mMaxSatiatedConsumptionLimit;
218     }
219 
220     @NonNull
221     @Override
getCostModifiers()222     int[] getCostModifiers() {
223         return COST_MODIFIERS;
224     }
225 
226     @Nullable
227     @Override
getAction(@ppAction int actionId)228     Action getAction(@AppAction int actionId) {
229         return mActions.get(actionId);
230     }
231 
232     @Nullable
233     @Override
getReward(@tilityReward int rewardId)234     Reward getReward(@UtilityReward int rewardId) {
235         return mRewards.get(rewardId);
236     }
237 
loadConstants(String policyValuesString, @Nullable DeviceConfig.Properties properties)238     private void loadConstants(String policyValuesString,
239             @Nullable DeviceConfig.Properties properties) {
240         mActions.clear();
241         mRewards.clear();
242 
243         try {
244             mParser.setString(policyValuesString);
245         } catch (IllegalArgumentException e) {
246             Slog.e(TAG, "Global setting key incorrect: ", e);
247         }
248 
249         mMinSatiatedBalanceOther = getConstantAsCake(mParser, properties,
250             KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
251         mMinSatiatedBalanceHeadlessSystemApp = getConstantAsCake(mParser, properties,
252                 KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
253                 DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
254                 mMinSatiatedBalanceOther);
255         mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
256                 KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
257                 DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
258                 mMinSatiatedBalanceHeadlessSystemApp);
259         mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
260             KEY_AM_MAX_SATIATED_BALANCE, DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
261             Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
262         mMinSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
263                 KEY_AM_MIN_CONSUMPTION_LIMIT, DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
264                 arcToCake(1));
265         mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
266                 KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
267                 mMinSatiatedConsumptionLimit);
268         mMaxSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
269                 KEY_AM_MAX_CONSUMPTION_LIMIT, DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
270                 mInitialSatiatedConsumptionLimit);
271 
272         final long exactAllowWhileIdleWakeupBasePrice = getConstantAsCake(mParser, properties,
273                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
274                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES);
275 
276         // Apps must hold the SCHEDULE_EXACT_ALARM or USE_EXACT_ALARMS permission in order to use
277         // exact alarms. Since the user has the option of granting/revoking the permission, we can
278         // be a little lenient on the action cost checks and only stop the action if the app has
279         // run out of credits, and not when the system has run out of stock.
280         mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
281                 new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
282                         getConstantAsCake(mParser, properties,
283                                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
284                                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES),
285                         exactAllowWhileIdleWakeupBasePrice,
286                         /* respectsStockLimit */ false));
287         mActions.put(ACTION_ALARM_WAKEUP_EXACT,
288                 new Action(ACTION_ALARM_WAKEUP_EXACT,
289                         getConstantAsCake(mParser, properties,
290                                 KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
291                                 DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES),
292                         getConstantAsCake(mParser, properties,
293                                 KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
294                                 DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES),
295                         /* respectsStockLimit */ false));
296 
297         final long inexactAllowWhileIdleWakeupBasePrice =
298                 getConstantAsCake(mParser, properties,
299                         KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
300                         DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES);
301 
302         mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
303                 new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
304                         getConstantAsCake(mParser, properties,
305                                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
306                                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES),
307                         inexactAllowWhileIdleWakeupBasePrice,
308                         /* respectsStockLimit */ false));
309         mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
310                 new Action(ACTION_ALARM_WAKEUP_INEXACT,
311                         getConstantAsCake(mParser, properties,
312                                 KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
313                                 DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES),
314                         getConstantAsCake(mParser, properties,
315                                 KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
316                                 DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES),
317                         /* respectsStockLimit */ false));
318 
319         final long exactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
320                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
321                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
322         mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
323                 new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
324                         getConstantAsCake(mParser, properties,
325                                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
326                                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES),
327                         exactAllowWhileIdleNonWakeupBasePrice,
328                         /* respectsStockLimit */ false));
329 
330         mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
331                 new Action(ACTION_ALARM_NONWAKEUP_EXACT,
332                         getConstantAsCake(mParser, properties,
333                                 KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
334                                 DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES),
335                         getConstantAsCake(mParser, properties,
336                                 KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
337                                 DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES),
338                         /* respectsStockLimit */ false));
339 
340         final long inexactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
341                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
342                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
343         final long inexactAllowWhileIdleNonWakeupCtp = getConstantAsCake(mParser, properties,
344                 KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
345                 DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES);
346         mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
347                 new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
348                         inexactAllowWhileIdleNonWakeupCtp,
349                         inexactAllowWhileIdleNonWakeupBasePrice));
350 
351         mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
352                 new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
353                         getConstantAsCake(mParser, properties,
354                                 KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
355                                 DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES),
356                         getConstantAsCake(mParser, properties,
357                                 KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
358                                 DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES)));
359         mActions.put(ACTION_ALARM_CLOCK,
360                 new Action(ACTION_ALARM_CLOCK,
361                         getConstantAsCake(mParser, properties,
362                                 KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
363                                 DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES),
364                         getConstantAsCake(mParser, properties,
365                                 KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
366                                 DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES),
367                         /* respectsStockLimit */ false));
368 
369         mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
370                 getConstantAsCake(mParser, properties,
371                         KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
372                         DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES),
373                 getConstantAsCake(mParser, properties,
374                         KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
375                         DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES),
376                 getConstantAsCake(mParser, properties,
377                         KEY_AM_REWARD_TOP_ACTIVITY_MAX,
378                         DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES)));
379         mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
380                 getConstantAsCake(mParser, properties,
381                         KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
382                         DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES),
383                 getConstantAsCake(mParser, properties,
384                         KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
385                         DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES),
386                 getConstantAsCake(mParser, properties,
387                         KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
388                         DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES)));
389         mRewards.put(REWARD_NOTIFICATION_INTERACTION,
390                 new Reward(REWARD_NOTIFICATION_INTERACTION,
391                         getConstantAsCake(mParser, properties,
392                                 KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
393                                 DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES),
394                         getConstantAsCake(mParser, properties,
395                                 KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
396                                 DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES),
397                         getConstantAsCake(mParser, properties,
398                                 KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
399                                 DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES)));
400         mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
401                 getConstantAsCake(mParser, properties,
402                         KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
403                         DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES),
404                 getConstantAsCake(mParser, properties,
405                         KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
406                         DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES),
407                 getConstantAsCake(mParser, properties,
408                         KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
409                         DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES)));
410         mRewards.put(REWARD_OTHER_USER_INTERACTION,
411                 new Reward(REWARD_OTHER_USER_INTERACTION,
412                         getConstantAsCake(mParser, properties,
413                                 KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
414                                 DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES),
415                         getConstantAsCake(mParser, properties,
416                                 KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
417                                 DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES),
418                         getConstantAsCake(mParser, properties,
419                                 KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
420                                 DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
421     }
422 
423     @Override
dump(IndentingPrintWriter pw)424     void dump(IndentingPrintWriter pw) {
425         pw.println("Min satiated balances:");
426         pw.increaseIndent();
427         pw.print("Exempted", cakeToString(mMinSatiatedBalanceExempted)).println();
428         pw.print("Other", cakeToString(mMinSatiatedBalanceOther)).println();
429         pw.decreaseIndent();
430         pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
431         pw.print("Consumption limits: [");
432         pw.print(cakeToString(mMinSatiatedConsumptionLimit));
433         pw.print(", ");
434         pw.print(cakeToString(mInitialSatiatedConsumptionLimit));
435         pw.print(", ");
436         pw.print(cakeToString(mMaxSatiatedConsumptionLimit));
437         pw.println("]");
438 
439         pw.println();
440         pw.println("Actions:");
441         pw.increaseIndent();
442         for (int i = 0; i < mActions.size(); ++i) {
443             dumpAction(pw, mActions.valueAt(i));
444         }
445         pw.decreaseIndent();
446 
447         pw.println();
448         pw.println("Rewards:");
449         pw.increaseIndent();
450         for (int i = 0; i < mRewards.size(); ++i) {
451             dumpReward(pw, mRewards.valueAt(i));
452         }
453         pw.decreaseIndent();
454     }
455 }
456