Android 13 添加安装应用密码输入框,更新不需要输入

介绍

此需求是在开发学生模式时,客户提到的一项功能,当学生模式开启时,不允许安装应用,同时adb命令也不可安装应用,只有输入正确密码才可以安装,但是已经安装的apk,允许正常安装无需输入密码,也就是更新不需要输入密码。

效果展示

Android 13 添加安装应用密码输入框,更新不需要输入_第1张图片

修改

首先我们定义一个开关的常量,当学生模式开启时启用此功能,如果不需要开关控制此处可不加。

路径:frameworks/base/core/java/android/provider/Settings.java

        /**soda water Child model
         * STUDENT_MODEL_SWITCH .
         * @hide
         */
        @Readable
public static final String STUDENT_MODEL_SWITCH = "student_model_switch";

添加需要用到的字符串资源 此处是密码输入失败时提示的消息和输入框的提示

路径:frameworks/base/packages/PackageInstaller/res/values/strings.xml


Incorrect password cannot be installed
Please enter your password

路径:frameworks/base/packages/PackageInstaller/res/values-zh-rCN/strings.xml

    
"密码错误 无法安装"
"请输入密码"

接着我们找到弹框的布局文件,在install_confirm_question_update后添加输入框
路径:frameworks/base/packages/PackageInstaller/res/layout/install_content_view.xml

    
   
    
   

此方法 startInstallConfirm() 是点击安装时触发的方法 ,在此方法中做如下修改 不需要开关控制的,可以删除对应student_model_switch的判断。

mOk.getText().toString().equals(getString(R.string.update) 此处用来判断是否未更新弹框如果是更新则可安装

路径:frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

//*/soda water Installation password  导入相关包
import android.widget.EditText;
import android.text.InputType;
import android.widget.Toast;
import android.content.ComponentName;
//*/


//*/soda water Installation password  定义输入框
private EditText studen_password;
//*/



private void startInstallConfirm() {
        View viewToEnable;
		//*/soda water Installation password  此处绑定控件
        studen_password = requireViewById(R.id.edit_student_passwork);
        if (mAppInfo != null) {
            viewToEnable = requireViewById(R.id.install_confirm_question_update);
            mOk.setText(R.string.update);
        } else {
            // This is a new application with no permissions.
            viewToEnable = requireViewById(R.id.install_confirm_question);
		//*/soda water Installation password  下面这段是当学生模式开启时显示输入框 不需要开关可删掉判断条件
        boolean studentSwitch = Settings.Global.getInt(getApplicationContext().getContentResolver(), "student_model_switch",0) != 0;
        if(studentSwitch){
        studen_password.setInputType(InputType.TYPE_CLASS_NUMBER);
        studen_password.setHint(R.string.student_hint_passwork);
        studen_password.setVisibility(View.VISIBLE);
        }

        Log.d("soda water", "install_confirm_question ");
		//*/
        }

        viewToEnable.setVisibility(View.VISIBLE);

        mEnableOk = true;
        mOk.setEnabled(true);
        mOk.setFilterTouchesWhenObscured(true);
}



private void bindUi() {
        mAlert.setIcon(mAppSnippet.icon);
        mAlert.setTitle(mAppSnippet.label);
        mAlert.setView(R.layout.install_content_view);
        mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
                (ignored, ignored2) -> {
                    if (mOk.isEnabled()) {
                        if (mSessionId != -1) {
                            mInstaller.setPermissionsResult(mSessionId, true);
                            finish();
                        } else {
				//*/soda water Installation password  此处加入判断 开启开关时我们获取输入框内容和student_password_global的密码进行比较 不正确则弹框 正确则执行安装方法startInstall
                            String password = Settings.Global.getString(getApplicationContext().getContentResolver(), "student_password_global");
                            boolean studentSwitch = Settings.Global.getInt(getApplicationContext().getContentResolver(), "student_model_switch",0) != 0;
                            if(studentSwitch){
                            if(password.equals(studen_password.getText().toString()) || mOk.getText().toString().equals(getString(R.string.update))){
                            sendBroadcast();
                            Log.d("soda water", "bindUi aaa ");
                            startInstall();
                            Log.d("soda water", "bindUi bbb ");
                            }else if(!password.equals(studen_password.getText().toString())){
                            Toast.makeText(getApplicationContext(), R.string.student_install_no, Toast.LENGTH_SHORT).show();
                            }
                            }else{
                            startInstall();
                            }


                            Log.d("soda water", "bindUi-1 "+studen_password.getText().toString());
							//*/
                        }
                    }
                }, null);
        mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                (ignored, ignored2) -> {
                    // Cancel and finish
                    setResult(RESULT_CANCELED);
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, false);
                    }
                    finish();
                }, null);
        setupAlert();

        mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
        mOk.setEnabled(false);

        if (!mOk.isInTouchMode()) {
            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
        }
}



//*/soda water  这个自定义的广播是用来判断是手动安装还是adb安装 后面会详细解释 如果不需要判断adb安装看到这里已经OK了 不调用此方法即可
private void sendBroadcast(){
        Intent intent = new Intent("action.phone.install");
        ComponentName componentName = new ComponentName("com.example.studentmodel","com.example.studentmodel.BootReceiver");
        intent.setComponent(componentName);
        sendBroadcast(intent);
}

不需要判断adb安装看到此处即可

接着我们看上一处发送的广播实际上这里主要是因为不能调用Settings.Global.putInt我才写广播进行标记的,正常接收器写在mtksettings的任意接收器也可以。

上面在密码输入正确时发送广播phone_install状态变为1

我的代码如下:

AndroidManifest.xml

        
            
                
            
        
package com.example.studentmodel;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;


public class BootReceiver extends BroadcastReceiver {
    private Context mContext;
    private static String ACTION_PHONE_INSTALL = "action.phone.install";

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
         if (intent.getAction().equals(ACTION_PHONE_INSTALL)) {
            Settings.Global.putInt(context.getContentResolver(), "phone_install", 1);
        }
    }

添加字符串资源

路径:frameworks/base/core/res/res/values/strings.xml

    disables ADB installation applications

路径:frameworks/base/core/res/res/values-zh-rCN/strings.xml

    "禁止ADB安装应用"

路径:frameworks/base/core/res/res/values/symbols.xml

  

接着我们来对adb安装进行限制 我们主要对doHandleMessage 方法中 INIT_COPY 做处理这是apk安装时一定会走到的 ,判断开关状态并且获取phone_install 的值判断是否为手动安装,如果是adb安装则执行return,这里我们接收前面提到的phone_install 在执行完判断后恢复为0。

路径:frameworks/base/services/core/java/com/android/server/pm/PackageHandler.java

//*/soda water Kiddie mode applies mounting switch  导包
import com.android.internal.R;
import android.widget.Toast;
//*/



//*/soda water Kiddie mode applies mounting switch
private boolean APK_INSTALL_SWITCH = false;
//*/


void doHandleMessage(Message msg) {
        switch (msg.what) {
            case INIT_COPY: {
                 //*/soda water Kiddie mode applies mounting switch
                 APK_INSTALL_SWITCH = Settings.Global.getInt(mPm.mContext.getContentResolver(),Settings.Global.STUDENT_MODEL_SWITCH,0) == 1;
                 boolean APK_INSTALL_IS_ADB = Settings.Global.getInt(mPm.mContext.getContentResolver(),"phone_install",0) == 0;
                 Log.d("soda water", "bindUi ccc "+Settings.Global.getInt(mPm.mContext.getContentResolver(),"phone_install",0));
                if(APK_INSTALL_SWITCH && APK_INSTALL_IS_ADB){
                 Toast.makeText(mPm.mContext,R.string.student_model_adb_apk_install, Toast.LENGTH_SHORT).show();
                 return;
                }
                 Settings.Global.putInt(mPm.mContext.getContentResolver(),"phone_install",0);
                 //*/soda water Kiddie mode applies mounting switch
                HandlerParams params = (HandlerParams) msg.obj;
                if (params != null) {
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                    Log.d("soda water","init_copy: "+params);
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                    params.startCopy();
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                break;
            }

你可能感兴趣的:(Android,13,android)