A13中,可以要求做一个开关来控制摄像头是否可用,约束所有使用摄像头的应用。思路:设置中增加开关设置一个属性值,在摄像头调用实现层增该值判断即可
一 开关的开发:
设置-安全中增加开关选项
代码部分:
Settings/res/xml/security_dashboard_settings.xml
//........忽略代码
<Preference
android:order="100"
android:key="security_advanced_settings"
android:title="@string/security_advanced_settings"
android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.security.SecurityAdvancedSettings"
settings:controller="com.android.settings.security.SecurityAdvancedSettingsController"
settings:keywords="@string/security_advanced_settings_keywords" />
<Preference
android:order="90"
android:title="@string/apk_install_setting">
<intent
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.security.ApkInstallActivity" />
</Preference>
+ <Preference
+ android:order="80"
+ android:title="@string/custom_function_control_setting">
+ <intent
+ android:targetPackage="com.android.settings"
+ +android:targetClass="com.android.settings.security.CustomFunctionSettingActivity" />
+ </Preference>
</PreferenceScreen>
新增界面,如下,自定义属性字段,可以参考上一篇文章Android SystemProperties 读写机制详解和案例使用 。就是使用开关组件读写属性
package com.android.settings.security;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.app.Activity;
import java.io.IOException;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.android.settings.R;
import android.provider.Settings;
import android.widget.Toast;
import android.text.TextUtils;
import android.os.SystemProperties;
import android.widget.CompoundButton;
import android.content.Context;
import android.widget.Switch;
/**
* 自定义功能开关
*/
public class CustomFunctionSettingActivity extends Activity implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
private Switch cameraSwbtn;
private static final String CAMERA_ENABLE_KEY = "persist.sys.flyscale.cam";
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
mContext = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_function_control);
cameraSwbtn = findViewById(R.id.swbtn_camera);
cameraSwbtn.setOnCheckedChangeListener(this);
String propValue = SystemProperties.get(CAMERA_ENABLE_KEY, "1"); // 默认启用
// String cameraEnable = Settings.Global.getString(getContentResolver(), Settings.Global.CUSTOM_FUNCTION_CAMERA_ENABLE);
if ("1".equals(propValue)) {
cameraSwbtn.setChecked(true);
}else {
cameraSwbtn.setChecked(false);
}
cameraSwbtn.setOnClickListener(this);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// switch (buttonView.getId()) {
// case R.id.toggle_button:
// Toast.makeText(this, "toggle state changed : " + isChecked, Toast.LENGTH_SHORT).show();
// break;
// case R.id.switch_button:
// Toast.makeText(this, "wlan state changed : " + isChecked, Toast.LENGTH_SHORT).show();
// break;
// default:
// Toast.makeText(this, "no state changed", Toast.LENGTH_SHORT).show();
// }
if (buttonView== null) {
return;
}
}
@Override
public void onClick(View v) {
if ( v == cameraSwbtn) {
boolean isChecked = cameraSwbtn.isChecked();
saveValue(isChecked);
if (isChecked) {
Toast.makeText(mContext, R.string.custom_function_camera_change_enable,Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(mContext, R.string.custom_function_camera_change_disable,Toast.LENGTH_SHORT).show();
}
}
}
private void saveValue(boolean enabled) {
String value = "0";
if (enabled) {
value = "1";
}else {
value = "0";
}
try {
SystemProperties.set(CAMERA_ENABLE_KEY, enabled ? "1" : "0");
} catch (Exception e) {
Log.e("CustomFunction", "Failed to set property", e);
}
// Settings.Global.putString(getContentResolver(), Settings.Global.CUSTOM_FUNCTION_CAMERA_ENABLE,value);
}
}
布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:text="@string/custom_function_control_setting"
android:textSize="24dp"
android:layout_margin="10dp"
android:gravity="center"
android:textColor="@android:color/black"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginTop="30dp"
android:orientation="horizontal">
<TextView
android:textSize="20dp"
android:layout_marginLeft="10dp"
android:text="@string/custom_function_control_camera_title"
android:gravity="center"
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<View android:layout_height="1dp"
android:layout_weight="1"
android:layout_width="0dp"/>
<Switch
android:id="@+id/swbtn_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:switchMinWidth="0dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"
android:showText="false"
android:switchPadding="10dp"
android:textOff="close"
android:textOn="open" />
</LinearLayout>
</LinearLayout>
二 摄像头控制逻辑添加:
//framework/av/services/camera/libcameraservice/CameraService.cpp 下
/**
* 控制摄像头开关是否允许使用
*/
const bool USING_CAMERA_ENABLE_LOCK = false;
。。。。。。。。。。。。忽略代码
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
const std::optional<String16>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;
int callingPid = CameraThreadState::getCallingPid();
bool systemNativeClient = false;
if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
std::string systemClient =
StringPrintf("client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = String16(systemClient.c_str());
systemNativeClient = true;
}
if (oomScoreOffset < 0) {
String8 msg =
String8::format("Cannot increase the priority of a client %s pid %d for "
"camera id %s", String8(clientPackageNameAdj).string(), callingPid,
id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
+ if (USING_CAMERA_ENABLE_LOCK) {
+ if (!isFlyscaleCameraEnabled()) {
+ String8 msg =
+ String8::format("flyscale camera not allow,Camera disabled by device +policy");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(ERROR_DISABLED, msg.string());
+ }
+
+ }
if (CameraServiceProxyWrapper::isCameraDisabled()) {
String8 msg =
String8::format("Camera disabled by device policy");
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_DISABLED, msg.string());
}
// enforce system camera permissions
if (oomScoreOffset > 0 &&
!hasPermissionsForSystemCamera(callingPid, CameraThreadState::getCallingUid())) {
String8 msg =
String8::format("Cannot change the priority of a client %s pid %d for "
"camera id %s without SYSTEM_CAMERA permissions",
String8(clientPackageNameAdj).string(), callingPid, id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.string());
}
。。。。。。。。。。。。。忽略代码
OVER~