Merge "Add OP_PLAY_AUDIO to control shutter sound." into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
da8e229b9c
@@ -18,19 +18,23 @@ package android.hardware;
|
||||
|
||||
import static android.system.OsConstants.*;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.IAudioService;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.renderscript.Allocation;
|
||||
@@ -43,6 +47,10 @@ import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
@@ -174,6 +182,15 @@ public class Camera {
|
||||
private boolean mFaceDetectionRunning = false;
|
||||
private final Object mAutoFocusCallbackLock = new Object();
|
||||
|
||||
private final Object mShutterSoundLock = new Object();
|
||||
// for AppOps
|
||||
private @Nullable IAppOpsService mAppOps;
|
||||
private IAppOpsCallback mAppOpsCallback;
|
||||
@GuardedBy("mShutterSoundLock")
|
||||
private boolean mHasAppOpsPlayAudio = true;
|
||||
@GuardedBy("mShutterSoundLock")
|
||||
private boolean mShutterSoundEnabledFromApp = true;
|
||||
|
||||
private static final int NO_ERROR = 0;
|
||||
|
||||
/**
|
||||
@@ -526,6 +543,7 @@ public class Camera {
|
||||
// Should never hit this.
|
||||
throw new RuntimeException("Unknown camera error");
|
||||
}
|
||||
initAppOps();
|
||||
}
|
||||
|
||||
|
||||
@@ -547,6 +565,33 @@ public class Camera {
|
||||
* An empty Camera for testing purpose.
|
||||
*/
|
||||
Camera() {
|
||||
initAppOps();
|
||||
}
|
||||
|
||||
private void initAppOps() {
|
||||
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
|
||||
mAppOps = IAppOpsService.Stub.asInterface(b);
|
||||
// initialize mHasAppOpsPlayAudio
|
||||
updateAppOpsPlayAudio();
|
||||
// register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
|
||||
mAppOpsCallback = new IAppOpsCallbackWrapper(this);
|
||||
try {
|
||||
mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
|
||||
ActivityThread.currentPackageName(), mAppOpsCallback);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error registering appOps callback", e);
|
||||
mHasAppOpsPlayAudio = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseAppOps() {
|
||||
try {
|
||||
if (mAppOps != null) {
|
||||
mAppOps.stopWatchingMode(mAppOpsCallback);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing to do here, the object is supposed to be released anyway
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -568,6 +613,7 @@ public class Camera {
|
||||
public final void release() {
|
||||
native_release();
|
||||
mFaceDetectionRunning = false;
|
||||
releaseAppOps();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1623,7 +1669,17 @@ public class Camera {
|
||||
Log.e(TAG, "Audio service is unavailable for queries");
|
||||
}
|
||||
}
|
||||
return _enableShutterSound(enabled);
|
||||
synchronized (mShutterSoundLock) {
|
||||
if (enabled && mHasAppOpsPlayAudio) {
|
||||
Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
|
||||
return false;
|
||||
}
|
||||
boolean ret = _enableShutterSound(enabled);
|
||||
if (ret) {
|
||||
mShutterSoundEnabledFromApp = enabled;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1648,6 +1704,49 @@ public class Camera {
|
||||
|
||||
private native final boolean _enableShutterSound(boolean enabled);
|
||||
|
||||
private static class IAppOpsCallbackWrapper extends IAppOpsCallback.Stub {
|
||||
private final WeakReference<Camera> mWeakCamera;
|
||||
|
||||
IAppOpsCallbackWrapper(Camera camera) {
|
||||
mWeakCamera = new WeakReference<Camera>(camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void opChanged(int op, int uid, String packageName) {
|
||||
if (op == AppOpsManager.OP_PLAY_AUDIO) {
|
||||
final Camera camera = mWeakCamera.get();
|
||||
if (camera != null) {
|
||||
camera.updateAppOpsPlayAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAppOpsPlayAudio() {
|
||||
synchronized (mShutterSoundLock) {
|
||||
boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
|
||||
try {
|
||||
int mode = AppOpsManager.MODE_IGNORED;
|
||||
if (mAppOps != null) {
|
||||
mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
|
||||
AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
|
||||
Process.myUid(), ActivityThread.currentPackageName());
|
||||
}
|
||||
mHasAppOpsPlayAudio = mode == AppOpsManager.MODE_ALLOWED;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "AppOpsService check audio operation failed");
|
||||
mHasAppOpsPlayAudio = false;
|
||||
}
|
||||
if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
|
||||
if (!mHasAppOpsPlayAudio) {
|
||||
_enableShutterSound(false);
|
||||
} else {
|
||||
_enableShutterSound(mShutterSoundEnabledFromApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for zoom changes during a smooth zoom operation.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user