Loading core/java/com/android/internal/util/ProgressReporter.java +96 −23 Original line number Diff line number Diff line Loading @@ -20,9 +20,12 @@ import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; import android.os.IProgressListener; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.MathUtils; import com.android.internal.annotations.GuardedBy; /** * Tracks and reports progress of a single task to a {@link IProgressListener}. * The reported progress of a task ranges from 0-100, but the task can be Loading @@ -44,33 +47,67 @@ import android.util.MathUtils; * } * </pre> * * This class is not thread safe. * * @hide */ public class ProgressReporter { public static final ProgressReporter NO_OP = new ProgressReporter(0, null); private static final int STATE_INIT = 0; private static final int STATE_STARTED = 1; private static final int STATE_FINISHED = 2; private final int mId; private final IProgressListener mListener; private Bundle mExtras = new Bundle(); @GuardedBy("this") private final RemoteCallbackList<IProgressListener> mListeners = new RemoteCallbackList<>(); @GuardedBy("this") private int mState = STATE_INIT; @GuardedBy("this") private int mProgress = 0; @GuardedBy("this") private Bundle mExtras = new Bundle(); /** * Current segment range: first element is starting progress of this * segment, second element is length of segment. */ @GuardedBy("this") private int[] mSegmentRange = new int[] { 0, 100 }; /** * Create a new task with the given identifier whose progress will be * reported to the given listener. */ public ProgressReporter(int id, @Nullable IProgressListener listener) { public ProgressReporter(int id) { mId = id; mListener = listener; } /** * Add given listener to watch for progress events. The current state will * be immediately dispatched to the given listener. */ public void addListener(@Nullable IProgressListener listener) { if (listener == null) return; synchronized (this) { mListeners.register(listener); switch (mState) { case STATE_INIT: // Nothing has happened yet break; case STATE_STARTED: try { listener.onStarted(mId, null); listener.onProgress(mId, mProgress, mExtras); } catch (RemoteException ignored) { } break; case STATE_FINISHED: try { listener.onFinished(mId, null); } catch (RemoteException ignored) { } break; } } } /** Loading Loading @@ -102,6 +139,10 @@ public class ProgressReporter { * Set the fractional progress of the currently active segment. */ public void setProgress(int n, int m, @Nullable CharSequence title) { synchronized (this) { if (mState != STATE_STARTED) { throw new IllegalStateException("Must be started to change progress"); } mProgress = mSegmentRange[0] + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]); if (title != null) { Loading @@ -109,6 +150,7 @@ public class ProgressReporter { } notifyProgress(mId, mProgress, mExtras); } } /** * Start a new inner segment that will contribute the given range towards Loading @@ -116,18 +158,22 @@ public class ProgressReporter { * {@link #endSegment(int[])} when finished. */ public int[] startSegment(int size) { synchronized (this) { final int[] lastRange = mSegmentRange; mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) }; return lastRange; } } /** * End the current segment. */ public void endSegment(int[] lastRange) { synchronized (this) { mProgress = mSegmentRange[0] + mSegmentRange[1]; mSegmentRange = lastRange; } } int getProgress() { return mProgress; Loading @@ -137,28 +183,55 @@ public class ProgressReporter { return mSegmentRange; } /** * Report this entire task as being started. */ public void start() { synchronized (this) { mState = STATE_STARTED; notifyStarted(mId, null); notifyProgress(mId, mProgress, mExtras); } } /** * Report this entire task as being finished. */ public void finish() { synchronized (this) { mState = STATE_FINISHED; notifyFinished(mId, null); mListeners.kill(); } } private void notifyStarted(int id, Bundle extras) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListeners.getBroadcastItem(i).onStarted(id, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } private void notifyProgress(int id, int progress, Bundle extras) { if (mListener != null) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListener.onProgress(id, progress, extras); mListeners.getBroadcastItem(i).onProgress(id, progress, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } public void notifyFinished(int id, Bundle extras) { if (mListener != null) { private void notifyFinished(int id, Bundle extras) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListener.onFinished(id, extras); mListeners.getBroadcastItem(i).onFinished(id, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } } core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ public class ProgressReporterTest extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); r = new ProgressReporter(0, null); r = new ProgressReporter(0); } private void assertProgress(int expected) { Loading services/core/java/com/android/server/am/ActivityManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -20676,7 +20676,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) { return mUserController.unlockUser(userId, token, secret, new ProgressReporter(0, listener)); return mUserController.unlockUser(userId, token, secret, listener); } @Override services/core/java/com/android/server/am/UserController.java +35 −27 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Process; Loading @@ -83,7 +84,6 @@ import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProgressReporter; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.pm.UserManagerService; Loading Loading @@ -260,7 +260,7 @@ final class UserController { * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. */ void finishUserUnlocking(final UserState uss, final ProgressReporter progress) { private void finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user Loading @@ -270,10 +270,13 @@ final class UserController { if (!isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { uss.mUnlockProgress.start(); // Prepare app storage before we go any further progress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); uss.mUnlockProgress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); mUserManager.onBeforeUnlockUser(userId); progress.setProgress(20); uss.mUnlockProgress.setProgress(20); // Dispatch unlocked to system services mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0)); Loading Loading @@ -306,15 +309,15 @@ final class UserController { // Send PRE_BOOT broadcasts if fingerprint changed final UserInfo info = getUserInfo(userId); if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) { progress.startSegment(80); new PreBootBroadcaster(mService, userId, progress) { uss.mUnlockProgress.startSegment(80); new PreBootBroadcaster(mService, userId, uss.mUnlockProgress) { @Override public void onFinished() { finishUserUnlocked(uss, progress); finishUserUnlocked(uss); } }.sendNext(); } else { finishUserUnlocked(uss, progress); finishUserUnlocked(uss); } } } Loading @@ -324,15 +327,15 @@ final class UserController { * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to * {@link UserState#STATE_RUNNING_UNLOCKED}. */ void finishUserUnlocked(UserState uss, ProgressReporter progress) { private void finishUserUnlocked(UserState uss) { try { finishUserUnlockedInternal(uss); } finally { progress.finish(); uss.mUnlockProgress.finish(); } } void finishUserUnlockedInternal(UserState uss) { private void finishUserUnlockedInternal(UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user Loading Loading @@ -860,7 +863,7 @@ final class UserController { return result; } boolean unlockUser(final int userId, byte[] token, byte[] secret, ProgressReporter progress) { boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: unlockUser() from pid=" Loading @@ -873,7 +876,7 @@ final class UserController { final long binderToken = Binder.clearCallingIdentity(); try { return unlockUserCleared(userId, token, secret, progress); return unlockUserCleared(userId, token, secret, listener); } finally { Binder.restoreCallingIdentity(binderToken); } Loading @@ -887,23 +890,29 @@ final class UserController { */ boolean maybeUnlockUser(final int userId) { // Try unlocking storage using empty token return unlockUserCleared(userId, null, null, ProgressReporter.NO_OP); return unlockUserCleared(userId, null, null, null); } private static void notifyFinished(int userId, IProgressListener listener) { if (listener == null) return; try { listener.onFinished(userId, null); } catch (RemoteException ignored) { } } boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, ProgressReporter progress) { IProgressListener listener) { final UserState uss; synchronized (mService) { // Bail if already running unlocked, or if not running at all final UserState uss = mStartedUsers.get(userId); // Bail if user isn't actually running, otherwise register the given // listener to watch for unlock progress uss = mStartedUsers.get(userId); if (uss == null) { progress.finish(); notifyFinished(userId, listener); return false; } switch (uss.state) { case STATE_RUNNING_UNLOCKING: case STATE_RUNNING_UNLOCKED: progress.finish(); return true; } else { uss.mUnlockProgress.addListener(listener); } } Loading @@ -914,14 +923,13 @@ final class UserController { mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret); } catch (RemoteException | RuntimeException e) { Slog.w(TAG, "Failed to unlock: " + e.getMessage()); progress.finish(); notifyFinished(userId, listener); return false; } } synchronized (mService) { final UserState uss = mStartedUsers.get(userId); finishUserUnlocking(uss, progress); finishUserUnlocking(uss); // We just unlocked a user, so let's now attempt to unlock any // managed profiles under that user. Loading services/core/java/com/android/server/am/UserState.java +7 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.server.am; import java.io.PrintWriter; import java.util.ArrayList; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; Loading @@ -28,6 +25,11 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.util.ProgressReporter; import java.io.PrintWriter; import java.util.ArrayList; public final class UserState { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM; Loading @@ -47,6 +49,7 @@ public final class UserState { public final UserHandle mHandle; public final ArrayList<IStopUserCallback> mStopCallbacks = new ArrayList<IStopUserCallback>(); public final ProgressReporter mUnlockProgress; public int state = STATE_BOOTING; public int lastState = STATE_BOOTING; Loading @@ -61,6 +64,7 @@ public final class UserState { public UserState(UserHandle handle) { mHandle = handle; mUnlockProgress = new ProgressReporter(handle.getIdentifier()); } public boolean setState(int oldState, int newState) { Loading Loading
core/java/com/android/internal/util/ProgressReporter.java +96 −23 Original line number Diff line number Diff line Loading @@ -20,9 +20,12 @@ import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; import android.os.IProgressListener; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.MathUtils; import com.android.internal.annotations.GuardedBy; /** * Tracks and reports progress of a single task to a {@link IProgressListener}. * The reported progress of a task ranges from 0-100, but the task can be Loading @@ -44,33 +47,67 @@ import android.util.MathUtils; * } * </pre> * * This class is not thread safe. * * @hide */ public class ProgressReporter { public static final ProgressReporter NO_OP = new ProgressReporter(0, null); private static final int STATE_INIT = 0; private static final int STATE_STARTED = 1; private static final int STATE_FINISHED = 2; private final int mId; private final IProgressListener mListener; private Bundle mExtras = new Bundle(); @GuardedBy("this") private final RemoteCallbackList<IProgressListener> mListeners = new RemoteCallbackList<>(); @GuardedBy("this") private int mState = STATE_INIT; @GuardedBy("this") private int mProgress = 0; @GuardedBy("this") private Bundle mExtras = new Bundle(); /** * Current segment range: first element is starting progress of this * segment, second element is length of segment. */ @GuardedBy("this") private int[] mSegmentRange = new int[] { 0, 100 }; /** * Create a new task with the given identifier whose progress will be * reported to the given listener. */ public ProgressReporter(int id, @Nullable IProgressListener listener) { public ProgressReporter(int id) { mId = id; mListener = listener; } /** * Add given listener to watch for progress events. The current state will * be immediately dispatched to the given listener. */ public void addListener(@Nullable IProgressListener listener) { if (listener == null) return; synchronized (this) { mListeners.register(listener); switch (mState) { case STATE_INIT: // Nothing has happened yet break; case STATE_STARTED: try { listener.onStarted(mId, null); listener.onProgress(mId, mProgress, mExtras); } catch (RemoteException ignored) { } break; case STATE_FINISHED: try { listener.onFinished(mId, null); } catch (RemoteException ignored) { } break; } } } /** Loading Loading @@ -102,6 +139,10 @@ public class ProgressReporter { * Set the fractional progress of the currently active segment. */ public void setProgress(int n, int m, @Nullable CharSequence title) { synchronized (this) { if (mState != STATE_STARTED) { throw new IllegalStateException("Must be started to change progress"); } mProgress = mSegmentRange[0] + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]); if (title != null) { Loading @@ -109,6 +150,7 @@ public class ProgressReporter { } notifyProgress(mId, mProgress, mExtras); } } /** * Start a new inner segment that will contribute the given range towards Loading @@ -116,18 +158,22 @@ public class ProgressReporter { * {@link #endSegment(int[])} when finished. */ public int[] startSegment(int size) { synchronized (this) { final int[] lastRange = mSegmentRange; mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) }; return lastRange; } } /** * End the current segment. */ public void endSegment(int[] lastRange) { synchronized (this) { mProgress = mSegmentRange[0] + mSegmentRange[1]; mSegmentRange = lastRange; } } int getProgress() { return mProgress; Loading @@ -137,28 +183,55 @@ public class ProgressReporter { return mSegmentRange; } /** * Report this entire task as being started. */ public void start() { synchronized (this) { mState = STATE_STARTED; notifyStarted(mId, null); notifyProgress(mId, mProgress, mExtras); } } /** * Report this entire task as being finished. */ public void finish() { synchronized (this) { mState = STATE_FINISHED; notifyFinished(mId, null); mListeners.kill(); } } private void notifyStarted(int id, Bundle extras) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListeners.getBroadcastItem(i).onStarted(id, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } private void notifyProgress(int id, int progress, Bundle extras) { if (mListener != null) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListener.onProgress(id, progress, extras); mListeners.getBroadcastItem(i).onProgress(id, progress, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } public void notifyFinished(int id, Bundle extras) { if (mListener != null) { private void notifyFinished(int id, Bundle extras) { for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { mListener.onFinished(id, extras); mListeners.getBroadcastItem(i).onFinished(id, extras); } catch (RemoteException ignored) { } } mListeners.finishBroadcast(); } }
core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ public class ProgressReporterTest extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); r = new ProgressReporter(0, null); r = new ProgressReporter(0); } private void assertProgress(int expected) { Loading
services/core/java/com/android/server/am/ActivityManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -20676,7 +20676,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) { return mUserController.unlockUser(userId, token, secret, new ProgressReporter(0, listener)); return mUserController.unlockUser(userId, token, secret, listener); } @Override
services/core/java/com/android/server/am/UserController.java +35 −27 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Process; Loading @@ -83,7 +84,6 @@ import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProgressReporter; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.pm.UserManagerService; Loading Loading @@ -260,7 +260,7 @@ final class UserController { * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. */ void finishUserUnlocking(final UserState uss, final ProgressReporter progress) { private void finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user Loading @@ -270,10 +270,13 @@ final class UserController { if (!isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { uss.mUnlockProgress.start(); // Prepare app storage before we go any further progress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); uss.mUnlockProgress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); mUserManager.onBeforeUnlockUser(userId); progress.setProgress(20); uss.mUnlockProgress.setProgress(20); // Dispatch unlocked to system services mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0)); Loading Loading @@ -306,15 +309,15 @@ final class UserController { // Send PRE_BOOT broadcasts if fingerprint changed final UserInfo info = getUserInfo(userId); if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) { progress.startSegment(80); new PreBootBroadcaster(mService, userId, progress) { uss.mUnlockProgress.startSegment(80); new PreBootBroadcaster(mService, userId, uss.mUnlockProgress) { @Override public void onFinished() { finishUserUnlocked(uss, progress); finishUserUnlocked(uss); } }.sendNext(); } else { finishUserUnlocked(uss, progress); finishUserUnlocked(uss); } } } Loading @@ -324,15 +327,15 @@ final class UserController { * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to * {@link UserState#STATE_RUNNING_UNLOCKED}. */ void finishUserUnlocked(UserState uss, ProgressReporter progress) { private void finishUserUnlocked(UserState uss) { try { finishUserUnlockedInternal(uss); } finally { progress.finish(); uss.mUnlockProgress.finish(); } } void finishUserUnlockedInternal(UserState uss) { private void finishUserUnlockedInternal(UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user Loading Loading @@ -860,7 +863,7 @@ final class UserController { return result; } boolean unlockUser(final int userId, byte[] token, byte[] secret, ProgressReporter progress) { boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: unlockUser() from pid=" Loading @@ -873,7 +876,7 @@ final class UserController { final long binderToken = Binder.clearCallingIdentity(); try { return unlockUserCleared(userId, token, secret, progress); return unlockUserCleared(userId, token, secret, listener); } finally { Binder.restoreCallingIdentity(binderToken); } Loading @@ -887,23 +890,29 @@ final class UserController { */ boolean maybeUnlockUser(final int userId) { // Try unlocking storage using empty token return unlockUserCleared(userId, null, null, ProgressReporter.NO_OP); return unlockUserCleared(userId, null, null, null); } private static void notifyFinished(int userId, IProgressListener listener) { if (listener == null) return; try { listener.onFinished(userId, null); } catch (RemoteException ignored) { } } boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, ProgressReporter progress) { IProgressListener listener) { final UserState uss; synchronized (mService) { // Bail if already running unlocked, or if not running at all final UserState uss = mStartedUsers.get(userId); // Bail if user isn't actually running, otherwise register the given // listener to watch for unlock progress uss = mStartedUsers.get(userId); if (uss == null) { progress.finish(); notifyFinished(userId, listener); return false; } switch (uss.state) { case STATE_RUNNING_UNLOCKING: case STATE_RUNNING_UNLOCKED: progress.finish(); return true; } else { uss.mUnlockProgress.addListener(listener); } } Loading @@ -914,14 +923,13 @@ final class UserController { mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret); } catch (RemoteException | RuntimeException e) { Slog.w(TAG, "Failed to unlock: " + e.getMessage()); progress.finish(); notifyFinished(userId, listener); return false; } } synchronized (mService) { final UserState uss = mStartedUsers.get(userId); finishUserUnlocking(uss, progress); finishUserUnlocking(uss); // We just unlocked a user, so let's now attempt to unlock any // managed profiles under that user. Loading
services/core/java/com/android/server/am/UserState.java +7 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.server.am; import java.io.PrintWriter; import java.util.ArrayList; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; Loading @@ -28,6 +25,11 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.util.ProgressReporter; import java.io.PrintWriter; import java.util.ArrayList; public final class UserState { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM; Loading @@ -47,6 +49,7 @@ public final class UserState { public final UserHandle mHandle; public final ArrayList<IStopUserCallback> mStopCallbacks = new ArrayList<IStopUserCallback>(); public final ProgressReporter mUnlockProgress; public int state = STATE_BOOTING; public int lastState = STATE_BOOTING; Loading @@ -61,6 +64,7 @@ public final class UserState { public UserState(UserHandle handle) { mHandle = handle; mUnlockProgress = new ProgressReporter(handle.getIdentifier()); } public boolean setState(int oldState, int newState) { Loading