前言
记录一些launchar开发的技术细节
清单里需要注意的内容
注意,要添加singleTask,否则会出现home键多次创建launchar 应用
<application> <activity android:name=".ui.MainActivity" android:exported="true" android:launchMode="singleTask"> <intent-filter> <!-- 隐藏图标 --> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <!-- 设置为 launcher --> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.rayland.home" /> </intent-filter> </activity> </application>
屏蔽一些按键防止launchar受影响
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { return true } if (keyCode == KeyEvent.KEYCODE_MENU) { return true } if (keyCode == KeyEvent.KEYCODE_HOME) { return true } }
启动桌面应用的方式
/** * 启动应用 */ fun startApp(packageName: String) { try { this@MainActivity.packageManager.getLaunchIntentForPackage(packageName)?.let { intent -> startActivity(intent) } } catch (e: Exception) { e.printStackTrace() Toast.makeText(this, "应用启动失败", Toast.LENGTH_SHORT).show() } } /** * 启动应用 * [packageName] 包名 * [className] 类名(请注意需要路径+类名) */ fun startApp(packageName: String, className: String) { try { startActivity(Intent().apply { setClassName(packageName, className) }) } catch (e: Exception) { e.printStackTrace() Log.e("zh", "应用启动失败 : $e" ) Toast.makeText(this, "应用启动失败", Toast.LENGTH_SHORT).show() } }
获取系统中安装的应用列表
bean
data class ApplyBean(val name: String?, val icon: Drawable?, val packageName: String?)
获取数据
private fun getAllApps(): List<ApplyBean> { val packageInfoArray = mutableListOf<PackageInfo>() val applyBeanArray = mutableListOf<ApplyBean>() val pManager = MainApp.getApp().packageManager // 获取手机内所有应用 val packlist = pManager.getInstalledPackages(0) for (i in packlist.indices) { val pak = packlist[i] as PackageInfo // if()里的值如果<=0则为自己装的程序,否则为系统工程自带 if (pak.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM <= 0) { // 添加自己已经安装的应用程序 packageInfoArray.add(pak) } else { //apps.add(pak) } } for (pinfo in packageInfoArray) { //设置图片 val icon = pManager.getApplicationIcon(pinfo.applicationInfo) //设置应用程序名字 val appName = pManager.getApplicationLabel(pinfo.applicationInfo).toString() //设置应用程序的包名 val packageName = pinfo.applicationInfo.packageName val app = ApplyBean(appName, icon, packageName) applyBeanArray.add(app) } return applyBeanArray }
应用变化监听
@Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED) || intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) || intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) { for (AppPackageListener appPackageListener: mAppPackageListener) { appPackageListener.onAppPackageChanged(intent.getAction(), intent.getData()); } } } public static void registerReceiver(Context context) { mIntentFilter = new IntentFilter(); mIntentFilter.addDataScheme("package"); mIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); mIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); mIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); context.registerReceiver(mReceiver, mIntentFilter); }
卸载应用
需要系统级权限
<!-- 卸载应用权限 系统级权限--> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" />
代码
不要吃惊,没错卸载是依靠一个系统activity实现的
/** * 卸载应用 */ fun uninstallApp(packageName: String) { try { val i: Intent = Intent.parseUri("#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;end", 0) .setData(Uri.fromParts("package", packageName, null)) .putExtra(Intent.EXTRA_USER, Process.myUserHandle()) this.startActivity(i) } catch (e: URISyntaxException) { Log.e("lwlx", "Failed to parse intent to start uninstall activity for item=$e") } }
上面卸载的来源,luancher3源码
/** * Performs the drop action and returns the target component for the dragObject or null if * the action was not performed. */ protected ComponentName performDropAction(View view, ItemInfo info) { if (mCurrentAccessibilityAction == RECONFIGURE) { int widgetId = getReconfigurableWidgetId(view); if (widgetId != INVALID_APPWIDGET_ID) { mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, -1); } return null; } // else: mCurrentAccessibilityAction == UNINSTALL ComponentName cn = getUninstallTarget(info); if (cn == null) { // System applications cannot be installed. For now, show a toast explaining that. // We may give them the option of disabling apps this way. Toast.makeText(mLauncher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show(); return null; } try { Intent i = Intent.parseUri(mLauncher.getString(R.string.delete_package_intent), 0) .setData(Uri.fromParts("package", cn.getPackageName(), cn.getClassName())) .putExtra(Intent.EXTRA_USER, info.user); mLauncher.startActivity(i); return cn; } catch (URISyntaxException e) { Log.e(TAG, "Failed to parse intent to start uninstall activity for item=" + info); return null; } }
其他设置
/** * 系统设置工具类 * 需要的系统级权限 * * <uses-permission android:name="android.permission.SET_TIME"/> * <uses-permission android:name="android.permission.SET_TIME_ZONE"/> * <uses-permission android:name="android.permission.WRITE_SETTINGS"/> * <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/> */ class SystemSettingsUtil { companion object { /** * 设置时间 */ fun setTime(context: Context, millis: Long) { val am: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager am.setTime(millis) } /** * 是否是24小时格式 * @return true=24小时 false=12小时 */ fun is24HourMode(context: Context): Boolean { return Settings.System.getString(context.contentResolver, Settings.System.TIME_12_24) == "24" } /** * 设置时间格式 * [is24HourMode] true=24小时 false=12小时 */ fun setHourMode(context: Context, is24HourMode: Boolean) { Settings.System.putString(context.contentResolver, Settings.System.TIME_12_24, if (is24HourMode) "24" else "12") } /** * 是否是自动校时 */ fun isAutoTime(context: Context) = Settings.Global.getInt(context.contentResolver, Settings.Global.AUTO_TIME, 0) == 1 /** * 设置自动校时 * [enable] 1=启用 0=禁用 */ fun setAutoTime(context: Context, enable: Int) { Settings.Global.putInt(context.contentResolver, Settings.Global.AUTO_TIME, enable) } /** * 设置亮度 */ fun setBrightness(context: Context, brightness: Int) { Settings.System.putInt(context.contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) Settings.System.putInt(context.contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness) } /** * 获取亮度 */ fun getBrightness(context: Context) = Settings.System.getInt(context.contentResolver, Settings.System.SCREEN_BRIGHTNESS) /** * 获取多媒体的声音音量 * * STREAM_VOICE_CALL 通话 * STREAM_SYSTEM 系统 * STREAM_RING 铃声 * STREAM_MUSIC 媒体音量 * STREAM_ALARM 闹钟 * STREAM_NOTIFICATION 通知 */ fun getMusicSound(context: Context) = (context.getSystemService(Context.AUDIO_SERVICE) as AudioManager).getStreamVolume(AudioManager.STREAM_MUSIC) /** * 获取多媒体的最大声音音量 * * STREAM_VOICE_CALL 通话 * STREAM_SYSTEM 系统 * STREAM_RING 铃声 * STREAM_MUSIC 媒体音量 * STREAM_ALARM 闹钟 * STREAM_NOTIFICATION 通知 */ fun getMaxMusicSound(context: Context) = (context.getSystemService(Context.AUDIO_SERVICE) as AudioManager).getStreamMaxVolume(AudioManager.STREAM_MUSIC) /** * 设置多媒体的声音音量 */ fun setMusicSound(context: Context, sound:Int) { //AudioManager.FLAG_SHOW_UI 调整音量时显示系统音量进度条 , 0 则不显示 //AudioManager.FLAG_ALLOW_RINGER_MODES 是否铃声模式 //AudioManager.FLAG_VIBRATE 是否震动模式 //AudioManager.FLAG_SHOW_VIBRATE_HINT 震动提示 //AudioManager.FLAG_SHOW_SILENT_HINT 静音提示 //AudioManager.FLAG_PLAY_SOUND 调整音量时播放声音 (context.getSystemService(Context.AUDIO_SERVICE) as AudioManager).setStreamVolume(AudioManager.STREAM_MUSIC, sound, AudioManager.FLAG_PLAY_SOUND) } } }
End