diff --git a/camera/Android.bp b/camera/Android.bp new file mode 100644 index 0000000..5ea1559 --- /dev/null +++ b/camera/Android.bp @@ -0,0 +1,22 @@ +// +// Copyright (C) 2023 ArrowOS +// +// SPDX-License-Identifier: Apache-2.0 +// + +android_app { + name: "DubaiCameraService", + srcs: ["src/**/*.java"], + certificate: "platform", + platform_apis: true, + privileged: true, + system_ext_specific: true, + required: ["privapp-permissions-dubaicameraservice.xml"], +} + +prebuilt_etc { + name: "privapp-permissions-dubaicameraservice.xml", + src: "privapp-permissions-dubaicameraservice.xml", + system_ext_specific: true, + sub_dir: "permissions", +} diff --git a/camera/AndroidManifest.xml b/camera/AndroidManifest.xml new file mode 100644 index 0000000..26526e5 --- /dev/null +++ b/camera/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/camera/privapp-permissions-dubaicameraservice.xml b/camera/privapp-permissions-dubaicameraservice.xml new file mode 100644 index 0000000..0b11906 --- /dev/null +++ b/camera/privapp-permissions-dubaicameraservice.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/camera/src/com/arrow/dubaicameraservice/BootReceiver.java b/camera/src/com/arrow/dubaicameraservice/BootReceiver.java new file mode 100644 index 0000000..206385b --- /dev/null +++ b/camera/src/com/arrow/dubaicameraservice/BootReceiver.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 ArrowOS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.arrow.dubaicameraservice; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class BootReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, Intent intent) { + if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) + return; + + DubaiCameraService.startService(context); + } +} diff --git a/camera/src/com/arrow/dubaicameraservice/DubaiCameraService.java b/camera/src/com/arrow/dubaicameraservice/DubaiCameraService.java new file mode 100644 index 0000000..195039a --- /dev/null +++ b/camera/src/com/arrow/dubaicameraservice/DubaiCameraService.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 ArrowOS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.arrow.dubaicameraservice; + +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static android.telephony.TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; +import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_NR; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.hardware.camera2.CameraManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.IBinder; +import android.os.Looper; +import android.os.UserHandle; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.Log; + +import java.util.concurrent.Executor; + +public class DubaiCameraService extends Service { + + private static final boolean DEBUG = false; + private static final String TAG = "DubaiCameraService"; + + private static final String FRONT_CAMERA_ID = "1"; + + private CameraManager mCameraManager; + private SubscriptionManager mSubManager; + private TelephonyManager mTelephonyManager; + + private boolean mIsFrontCamInUse = false; + private int mSubId = INVALID_SUBSCRIPTION_ID; + + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final Executor mExecutor = new HandlerExecutor(mHandler); + + private final CameraManager.AvailabilityCallback mCameraCallback = + new CameraManager.AvailabilityCallback() { + @Override + public void onCameraAvailable(String cameraId) { + dlog("onCameraAvailable id:" + cameraId); + if (cameraId.equals(FRONT_CAMERA_ID)) { + mIsFrontCamInUse = false; + update5gState(); + } + } + + @Override + public void onCameraUnavailable(String cameraId) { + dlog("onCameraUnavailable id:" + cameraId); + if (cameraId.equals(FRONT_CAMERA_ID)) { + mIsFrontCamInUse = true; + update5gState(); + } + } + }; + + private final SubscriptionManager.OnSubscriptionsChangedListener mSubListener = + new SubscriptionManager.OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + dlog("onSubscriptionsChanged"); + update5gState(); + } + }; + + private class ActiveDataSubIdCallback extends TelephonyCallback implements + TelephonyCallback.ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + dlog("onActiveDataSubscriptionIdChanged subId:" + subId); + mSubId = subId; + update5gState(); + } + }; + + private final TelephonyCallback mTelephonyCallback = new ActiveDataSubIdCallback(); + + @Override + public void onCreate() { + dlog("onCreate"); + mCameraManager = getSystemService(CameraManager.class); + mSubManager = getSystemService(SubscriptionManager.class); + mTelephonyManager = getSystemService(TelephonyManager.class); + + mCameraManager.registerAvailabilityCallback(mCameraCallback, mHandler); + mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback); + mSubManager.addOnSubscriptionsChangedListener(mExecutor, mSubListener); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + dlog("onStartCommand"); + return START_STICKY; + } + + @Override + public void onDestroy() { + dlog("onDestroy"); + mCameraManager.unregisterAvailabilityCallback(mCameraCallback); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); + mSubManager.removeOnSubscriptionsChangedListener(mSubListener); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public static void startService(Context context) { + Log.i(TAG, "Starting service"); + context.startServiceAsUser(new Intent(context, DubaiCameraService.class), + UserHandle.CURRENT); + } + + private void update5gState() { + if (mSubId == INVALID_SUBSCRIPTION_ID + || mSubManager.getActiveSubscriptionIdList().length <= 0) { + dlog("update5gState: Invalid subid or no active subs!"); + return; + } + final TelephonyManager tm = mTelephonyManager.createForSubscriptionId(mSubId); + // Arguably we should use ALLOWED_NETWORK_TYPES_REASON_POWER here but that's already + // used by battery saver, and we are out of other reasons + long allowedNetworkTypes = tm.getAllowedNetworkTypesForReason( + ALLOWED_NETWORK_TYPES_REASON_CARRIER); + final boolean is5gAllowed = (allowedNetworkTypes & NETWORK_TYPE_BITMASK_NR) != 0; + dlog("update5gState mIsFrontCamInUse:" + mIsFrontCamInUse + " is5gAllowed:" + is5gAllowed); + if (mIsFrontCamInUse && is5gAllowed) { + allowedNetworkTypes &= ~NETWORK_TYPE_BITMASK_NR; + } else if (!mIsFrontCamInUse && !is5gAllowed) { + allowedNetworkTypes |= NETWORK_TYPE_BITMASK_NR; + } else { + return; + } + tm.setAllowedNetworkTypesForReason(ALLOWED_NETWORK_TYPES_REASON_CARRIER, + allowedNetworkTypes); + } + + private static void dlog(String msg) { + if (DEBUG) Log.d(TAG, msg); + } +} diff --git a/device.mk b/device.mk index c5adcc9..afa5475 100644 --- a/device.mk +++ b/device.mk @@ -55,6 +55,7 @@ PRODUCT_COPY_FILES += \ # Camera PRODUCT_PACKAGES += \ + DubaiCameraService \ libgui_shim_vendor # Fingerprint