content: /*
   * Copyright (C) 2014 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 android.app.trust;
  
  import android.Manifest;
  import android.annotation.RequiresPermission;
  import android.annotation.SystemService;
  import android.annotation.UnsupportedAppUsage;
  import android.content.Context;
  import android.hardware.biometrics.BiometricSourceType;
  import android.os.Handler;
  import android.os.IBinder;
  import android.os.Looper;
  import android.os.Message;
  import android.os.RemoteException;
  import android.util.ArrayMap;
  
  /**
   * See {@link com.android.server.trust.TrustManagerService}
   * @hide
   */
  @SystemService(Context.TRUST_SERVICE)
  public class TrustManager {
  
      private static final int MSG_TRUST_CHANGED = 1;
      private static final int MSG_TRUST_MANAGED_CHANGED = 2;
      private static final int MSG_TRUST_ERROR = 3;
  
      private static final String TAG = "TrustManager";
      private static final String DATA_FLAGS = "initiatedByUser";
      private static final String DATA_MESSAGE = "message";
  
      private final ITrustManager mService;
      private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
  
      public TrustManager(IBinder b) {
          mService = ITrustManager.Stub.asInterface(b);
          mTrustListeners = new ArrayMap<TrustListener, ITrustListener>();
      }
  
      /**
       * Changes the lock status for the given user. This is only applicable to Managed Profiles,
       * other users should be handled by Keyguard.
       *
       * @param userId The id for the user to be locked/unlocked.
       * @param locked The value for that user's locked state.
       */
      @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
      public void setDeviceLockedForUser(int userId, boolean locked) {
          try {
              mService.setDeviceLockedForUser(userId, locked);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Reports that user {@param userId} has tried to unlock the device.
       *
       * @param successful if true, the unlock attempt was successful.
       *
       * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
       */
      @UnsupportedAppUsage
      public void reportUnlockAttempt(boolean successful, int userId) {
          try {
              mService.reportUnlockAttempt(successful, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Reports that user {@param userId} has entered a temporary device lockout.
       *
       * This generally occurs when  the user has unsuccessfully tried to unlock the device too many
       * times. The user will then be unable to unlock the device until a set amount of time has
       * elapsed.
       *
       * @param timeout The amount of time that needs to elapse, in milliseconds, until the user may
       *    attempt to unlock the device again.
       *
       * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
       */
      public void reportUnlockLockout(int timeoutMs, int userId) {
          try {
              mService.reportUnlockLockout(timeoutMs, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Reports that the list of enabled trust agents changed for user {@param userId}.
       *
       * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
       */
      public void reportEnabledTrustAgentsChanged(int userId) {
          try {
              mService.reportEnabledTrustAgentsChanged(userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Reports that the visibility of the keyguard has changed.
       *
       * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
       */
      public void reportKeyguardShowingChanged() {
          try {
              mService.reportKeyguardShowingChanged();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Registers a listener for trust events.
       *
       * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
       */
      public void registerTrustListener(final TrustListener trustListener) {
          try {
              ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
                  @Override
                  public void onTrustChanged(boolean enabled, int userId, int flags) {
                      Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
                              trustListener);
                      if (flags != 0) {
                          m.getData().putInt(DATA_FLAGS, flags);
                      }
                      m.sendToTarget();
                  }
  
                  @Override
                  public void onTrustManagedChanged(boolean managed, int userId) {
                      mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId,
                              trustListener).sendToTarget();
                  }
  
                  @Override
                  public void onTrustError(CharSequence message) {
                      Message m = mHandler.obtainMessage(MSG_TRUST_ERROR);
                      m.getData().putCharSequence(DATA_MESSAGE, message);
                      m.sendToTarget();
                  }
              };
              mService.registerTrustListener(iTrustListener);
              mTrustListeners.put(trustListener, iTrustListener);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Unregisters a listener for trust events.
       *
       * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
       */
      public void unregisterTrustListener(final TrustListener trustListener) {
          ITrustListener iTrustListener = mTrustListeners.remove(trustListener);
          if (iTrustListener != null) {
              try {
                  mService.unregisterTrustListener(iTrustListener);
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
          }
      }
  
      /**
       * @return whether {@param userId} has enabled and configured trust agents. Ignores short-term
       * unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}.
       */
      @RequiresPermission(android.Manifest.permission.TRUST_LISTENER)
      public boolean isTrustUsuallyManaged(int userId) {
          try {
              return mService.isTrustUsuallyManaged(userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Updates the trust state for the user due to the user unlocking via a biometric sensor.
       * Should only be called if user authenticated via fingerprint, face, or iris and bouncer
       * can be skipped.
       *
       * @param userId
       */
      @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
      public void unlockedByBiometricForUser(int userId, BiometricSourceType source) {
          try {
              mService.unlockedByBiometricForUser(userId, source);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Clears authentication by the specified biometric type for all users.
       */
      @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
      public void clearAllBiometricRecognized(BiometricSourceType source) {
          try {
              mService.clearAllBiometricRecognized(source);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      private final Handler mHandler = new Handler(Looper.getMainLooper()) {
          @Override
          public void handleMessage(Message msg) {
              switch(msg.what) {
                  case MSG_TRUST_CHANGED:
                      int flags = msg.peekData() != null ? msg.peekData().getInt(DATA_FLAGS) : 0;
                      ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags);
                      break;
                  case MSG_TRUST_MANAGED_CHANGED:
                      ((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
                      break;
                  case MSG_TRUST_ERROR:
                      final CharSequence message = msg.peekData().getCharSequence(DATA_MESSAGE);
                      ((TrustListener)msg.obj).onTrustError(message);
              }
          }
      };
  
      public interface TrustListener {
  
          /**
           * Reports that the trust state has changed.
           * @param enabled If true, the system believes the environment to be trusted.
           * @param userId The user, for which the trust changed.
           * @param flags Flags specified by the trust agent when granting trust. See
           *     {@link android.service.trust.TrustAgentService#grantTrust(CharSequence, long, int)
           *                 TrustAgentService.grantTrust(CharSequence, long, int)}.
           */
          void onTrustChanged(boolean enabled, int userId, int flags);
  
          /**
           * Reports that whether trust is managed has changed
           * @param enabled If true, at least one trust agent is managing trust.
           * @param userId The user, for which the state changed.
           */
          void onTrustManagedChanged(boolean enabled, int userId);
  
          /**
           * Reports that an error happened on a TrustAgentService.
           * @param message A message that should be displayed on the UI.
           */
          void onTrustError(CharSequence message);
      }
  }
  