1 /*
2  * Copyright (C) 2018 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.example.android.systemupdatersample;
18 
19 import android.util.SparseArray;
20 
21 import com.google.common.collect.ImmutableMap;
22 import com.google.common.collect.ImmutableSet;
23 
24 import java.util.concurrent.atomic.AtomicInteger;
25 
26 /**
27  * Controls updater state.
28  */
29 public class UpdaterState {
30 
31     public static final int IDLE = 0;
32     public static final int ERROR = 1;
33     public static final int RUNNING = 2;
34     public static final int PAUSED = 3;
35     public static final int SLOT_SWITCH_REQUIRED = 4;
36     public static final int REBOOT_REQUIRED = 5;
37 
38     private static final SparseArray<String> STATE_MAP = new SparseArray<>();
39 
40     static {
41         STATE_MAP.put(0, "IDLE");
42         STATE_MAP.put(1, "ERROR");
43         STATE_MAP.put(2, "RUNNING");
44         STATE_MAP.put(3, "PAUSED");
45         STATE_MAP.put(4, "SLOT_SWITCH_REQUIRED");
46         STATE_MAP.put(5, "REBOOT_REQUIRED");
47     }
48 
49     /**
50      * Allowed state transitions. It's a map: key is a state, value is a set of states that
51      * are allowed to transition to from key.
52      */
53     private static final ImmutableMap<Integer, ImmutableSet<Integer>> TRANSITIONS =
54             ImmutableMap.<Integer, ImmutableSet<Integer>>builder()
55                     .put(IDLE, ImmutableSet.of(IDLE, ERROR, RUNNING))
56                     .put(ERROR, ImmutableSet.of(IDLE))
57                     .put(RUNNING, ImmutableSet.of(
58                             IDLE, ERROR, PAUSED, REBOOT_REQUIRED, SLOT_SWITCH_REQUIRED))
59                     .put(PAUSED, ImmutableSet.of(ERROR, RUNNING, IDLE))
60                     .put(SLOT_SWITCH_REQUIRED, ImmutableSet.of(ERROR, REBOOT_REQUIRED, IDLE))
61                     .put(REBOOT_REQUIRED, ImmutableSet.of(IDLE))
62                     .build();
63 
64     private AtomicInteger mState;
65 
UpdaterState(int state)66     public UpdaterState(int state) {
67         this.mState = new AtomicInteger(state);
68     }
69 
70     /**
71      * Returns updater state.
72      */
get()73     public int get() {
74         return mState.get();
75     }
76 
77     /**
78      * Sets the updater state.
79      *
80      * @throws InvalidTransitionException if transition is not allowed.
81      */
set(int newState)82     public void set(int newState) throws InvalidTransitionException {
83         int oldState = mState.get();
84         if (!TRANSITIONS.get(oldState).contains(newState)) {
85             throw new InvalidTransitionException(
86                     "Can't transition from " + oldState + " to " + newState);
87         }
88         mState.set(newState);
89     }
90 
91     /**
92      * Converts status code to status name.
93      */
getStateText(int state)94     public static String getStateText(int state) {
95         return STATE_MAP.get(state);
96     }
97 
98     /**
99      * Defines invalid state transition exception.
100      */
101     public static class InvalidTransitionException extends Exception {
InvalidTransitionException(String msg)102         public InvalidTransitionException(String msg) {
103             super(msg);
104         }
105     }
106 }
107