content: /*
   * Copyright (C) 2013 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.server.location;
  
  import android.annotation.Nullable;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.Intent;
  import android.content.ServiceConnection;
  import android.hardware.location.GeofenceHardwareService;
  import android.hardware.location.IGeofenceHardware;
  import android.location.IFusedGeofenceHardware;
  import android.location.IGeofenceProvider;
  import android.location.IGpsGeofenceHardware;
  import android.os.IBinder;
  import android.os.RemoteException;
  import android.os.UserHandle;
  import android.util.Log;
  
  import com.android.server.FgThread;
  import com.android.server.ServiceWatcher;
  
  /**
   * @hide
   */
  public final class GeofenceProxy {
  
      private static final String TAG = "GeofenceProxy";
      private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider";
  
      private final Context mContext;
      private final ServiceWatcher mServiceWatcher;
  
      @Nullable
      private final IGpsGeofenceHardware mGpsGeofenceHardware;
      @Nullable
      private final IFusedGeofenceHardware mFusedGeofenceHardware;
  
      private volatile IGeofenceHardware mGeofenceHardware;
  
      private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> {
          IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
          try {
              provider.setGeofenceHardware(mGeofenceHardware);
          } catch (RemoteException e) {
              Log.w(TAG, e);
          }
      };
  
      public static GeofenceProxy createAndBind(Context context,
              int overlaySwitchResId, int defaultServicePackageNameResId,
              int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
              @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
          GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
                  defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence,
                  fusedGeofenceHardware);
  
          if (proxy.bind()) {
              return proxy;
          } else {
              return null;
          }
      }
  
      private GeofenceProxy(Context context,
              int overlaySwitchResId, int defaultServicePackageNameResId,
              int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
              @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
          mContext = context;
          mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
                  defaultServicePackageNameResId, initialPackageNamesResId,
                  FgThread.getHandler()) {
              @Override
              protected void onBind() {
                  runOnBinder(mUpdateGeofenceHardware);
              }
          };
  
          mGpsGeofenceHardware = gpsGeofence;
          mFusedGeofenceHardware = fusedGeofenceHardware;
  
          mGeofenceHardware = null;
      }
  
      private boolean bind() {
          if (mServiceWatcher.start()) {
              mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
                      new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE,
                      UserHandle.SYSTEM);
              return true;
          }
  
          return false;
      }
  
      private class GeofenceProxyServiceConnection implements ServiceConnection {
  
          @Override
          public void onServiceConnected(ComponentName name, IBinder service) {
              IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service);
  
              try {
                  if (mGpsGeofenceHardware != null) {
                      geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
                  }
                  if (mFusedGeofenceHardware != null) {
                      geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
                  }
  
                  mGeofenceHardware = geofenceHardware;
                  mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
              } catch (Exception e) {
                  Log.w(TAG, e);
              }
          }
  
          @Override
          public void onServiceDisconnected(ComponentName name) {
              mGeofenceHardware = null;
              mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
          }
      }
  }
  