拷贝APP_Bck20250119项目源码,移除libjc/jcc/libs/android-29.jar文件。
This commit is contained in:
		
							
								
								
									
										1
									
								
								autoinstaller/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								autoinstaller/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
|  | ||||
							
								
								
									
										70
									
								
								autoinstaller/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								autoinstaller/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "33.0.3" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.autoinstaller" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 2 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "5.0"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     compileOptions { | ||||
|         sourceCompatibility JavaVersion.VERSION_11 | ||||
|         targetCompatibility JavaVersion.VERSION_11 | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| 	api 'cc.winboll.studio:winboll-shared:1.1.0' | ||||
|     api 'io.github.medyo:android-about-page:2.0.0' | ||||
|     api 'com.github.getActivity:ToastUtils:10.5' | ||||
|     api 'com.jcraft:jsch:0.1.55' | ||||
|     api 'org.jsoup:jsoup:1.13.1' | ||||
|     api 'com.squareup.okhttp3:okhttp:4.4.1' | ||||
|      | ||||
|     api 'androidx.appcompat:appcompat:1.0.0' | ||||
|     api 'androidx.fragment:fragment:1.0.0' | ||||
|     api 'com.google.android.material:material:1.0.0' | ||||
|      | ||||
|     api 'androidx.vectordrawable:vectordrawable-animated:1.0.0' | ||||
|     api 'androidx.lifecycle:lifecycle-livedata:1.0.0' | ||||
|      | ||||
|     //api 'cc.winboll.studio:libaes:6.3.2' | ||||
|     //api 'cc.winboll.studio:libapputils:8.3.8' | ||||
|      | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
| } | ||||
							
								
								
									
										8
									
								
								autoinstaller/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								autoinstaller/build.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Jan 02 02:39:56 HKT 2025 | ||||
| stageCount=4 | ||||
| libraryProject= | ||||
| baseVersion=5.0 | ||||
| publishVersion=5.0.3 | ||||
| buildCount=0 | ||||
| baseBetaVersion=5.0.4 | ||||
							
								
								
									
										17
									
								
								autoinstaller/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								autoinstaller/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
|  | ||||
| # Add any project specific keep options here: | ||||
|  | ||||
| # If your project uses WebView with JS, uncomment the following | ||||
| # and specify the fully qualified class name to the JavaScript interface | ||||
| # class: | ||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||
| #   public *; | ||||
| #} | ||||
							
								
								
									
										22
									
								
								autoinstaller/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								autoinstaller/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <provider | ||||
|             android:name="androidx.core.content.FileProvider" | ||||
|             android:authorities="cc.winboll.studio.autoinstaller.beta.fileprovider" | ||||
|             android:exported="false" | ||||
|             android:grantUriPermissions="true"> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.support.FILE_PROVIDER_PATHS" | ||||
|                 android:resource="@xml/provider_paths"/> | ||||
|  | ||||
|         </provider> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								autoinstaller/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								autoinstaller/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">AutoInstaller☆</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										73
									
								
								autoinstaller/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								autoinstaller/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.autoinstaller"> | ||||
|  | ||||
|     <!-- 读取您共享存储空间中的内容 --> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <!-- 修改或删除您共享存储空间中的内容 --> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <!-- 请求安装文件包 --> | ||||
|     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> | ||||
|  | ||||
|     <!-- 运行前台服务 --> | ||||
|     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> | ||||
|  | ||||
|     <!-- 此应用可显示在其他应用上方 --> | ||||
|     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | ||||
|  | ||||
|     <!-- 开机启动 --> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> | ||||
|  | ||||
|     <!-- MANAGE_EXTERNAL_STORAGE --> | ||||
|     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@drawable/ic_winboll" | ||||
|         android:label="@string/app_name" | ||||
|         android:roundIcon="@drawable/ic_winboll" | ||||
|         android:persistent="true" | ||||
|         android:supportsRtl="true" | ||||
|         android:requestLegacyExternalStorage="true" | ||||
|         android:theme="@style/Theme.Application"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="false"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <service android:name=".services.MainService"/> | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.MainReceiver" | ||||
|             android:enabled="true" | ||||
|             android:exported="false" | ||||
|             android:directBootAware="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.BOOT_COMPLETED"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| @@ -0,0 +1,31 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/04/28 02:39:58 | ||||
|  * @Describe 全局应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import cc.winboll.studio.shared.app.WinBollApplication; | ||||
|  | ||||
| public class App extends WinBollApplication { | ||||
|      | ||||
|     public static final String TAG = "App"; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         setIsDebug(BuildConfig.DEBUG); | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.toast_custom_view); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|     } | ||||
| } | ||||
|  | ||||
|      | ||||
|      | ||||
|      | ||||
| @@ -0,0 +1,80 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| import android.os.FileObserver; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class FileListener extends FileObserver { | ||||
| 	public final static String TAG = "FileListener"; | ||||
|  | ||||
|     public EventCallback callback; | ||||
|  | ||||
|     public FileListener(String path) { | ||||
| 		super(path); | ||||
| 		LogUtils.i(TAG, "File Listener to : " + path); | ||||
|     } | ||||
|     public void setEventCallback(EventCallback callback) { | ||||
|         this.callback = callback; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onEvent(int event, String path) { | ||||
|         //LogUtils.d(TAG, "path : "+path); | ||||
|  | ||||
|  | ||||
|         //int e = event & FileObserver.ALL_EVENTS; | ||||
|         int e = event & FileObserver.CLOSE_WRITE; | ||||
|         //LogUtils.d(TAG, "event->e:"+e); | ||||
|         switch (e) { | ||||
|             case FileObserver.ACCESS: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__1打开文件后读取文件的操作"); | ||||
|                 break; | ||||
|             case FileObserver.MODIFY: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__2文件被修改"); | ||||
|                 break; | ||||
|             case FileObserver.ATTRIB: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__4属性变化"); | ||||
|                 break; | ||||
|             case FileObserver.CLOSE_WRITE: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__8文件写入或编辑后关闭"); | ||||
| 				callback.onEvent(path); | ||||
|                 break; | ||||
|             case FileObserver.CLOSE_NOWRITE: | ||||
|                 //录音时,最后一个有效回调是这个 | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__16只读文件被关闭"); | ||||
|  | ||||
|                 //callback.onEvent(path); | ||||
|  | ||||
|  | ||||
|                 break; | ||||
|             case FileObserver.OPEN: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__32文件被打开"); | ||||
|                 break; | ||||
|             case FileObserver.MOVED_FROM: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__64移出事件");//试了重命名先MOVED_FROM再MOVED_TO | ||||
|                 break; | ||||
|             case FileObserver.MOVED_TO: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__128移入事件"); | ||||
|                 break; | ||||
|             case FileObserver.CREATE: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__256新建文件");//把文件移动给自己先CREATE在DELETE | ||||
|                 break; | ||||
|             case FileObserver.DELETE: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__512有删除文件");//把文件移出去DELETE | ||||
|                 break; | ||||
|             case FileObserver.DELETE_SELF: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__1024监听的这个文件夹被删除"); | ||||
|                 break; | ||||
|             case FileObserver.MOVE_SELF: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__2048监听的这个文件夹被移走"); | ||||
|                 break; | ||||
|             case FileObserver.ALL_EVENTS: | ||||
|                 //LogUtils.d(TAG, "文件操作___" + e + "__4095全部操作"); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| 	public interface EventCallback { | ||||
|         void onEvent(String path); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,312 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.graphics.Color; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import android.widget.EditText; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.SimpleAdapter; | ||||
| import android.widget.Switch; | ||||
| import android.widget.TextClock; | ||||
| import android.widget.Toast; | ||||
| import androidx.core.content.FileProvider; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.shared.log.LogView; | ||||
| import cc.winboll.studio.autoinstaller.MainActivity; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.autoinstaller.utils.NotificationUtil; | ||||
| import cc.winboll.studio.autoinstaller.views.ListViewForScrollView; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class MainActivity extends Activity { | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     private static final int INSTALL_PERMISSION_CODE = 1; | ||||
|  | ||||
|     LogView mLogView; | ||||
|     TextClock mTextClock; | ||||
|     EditText mEditText; | ||||
|     Switch mSwitch; | ||||
|     //sharedPreferences shPrefs; | ||||
|  | ||||
|     SimpleAdapter mSimpleAdapter; | ||||
|     static String MAP_NAME = "NAME"; | ||||
|     List<Map<String,Object>> mAdapterData = new ArrayList<>(); | ||||
|     ListViewForScrollView mListViewForScrollView; | ||||
|     String szAPKFileName; | ||||
| 	String szAPKFilePath; | ||||
|  | ||||
|     public static final String ACTION_NEW_INSTALLTASK = MainActivity.class.getName() + ".ACTION_NEW_INSTALLTASK"; | ||||
|     public static final String EXTRA_INSTALLED_PACKAGENAME = "EXTRA_INSTALLED_PACKAGENAME"; | ||||
|     public static final String EXTRA_INSTALLED_APKFILEPATH = "EXTRA_INSTALLED_APKFILEPATH"; | ||||
|     public static int REQUEST_CODE_ON_INSTALL_COMPLETED = 0; | ||||
|  | ||||
|     String mszInstalledPackageName = ""; | ||||
|     String mszInstalledAPKFilePath = ""; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
| 		// Remove this line if you don't want AndroidIDE to show this app's logs | ||||
| 		//LogSender.startLogging(this); | ||||
|  | ||||
|         super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_main); | ||||
|         initView(); | ||||
|  | ||||
|         if (getIntent().getAction().equals(ACTION_NEW_INSTALLTASK)) { | ||||
|             mszInstalledPackageName = getIntent().getStringExtra(EXTRA_INSTALLED_PACKAGENAME); | ||||
|             mszInstalledAPKFilePath = getIntent().getStringExtra(EXTRA_INSTALLED_APKFILEPATH); | ||||
|             installAPK(); | ||||
|         } | ||||
|  | ||||
|         //LogUtils.d(TAG, "Hello, World!"); | ||||
| 	} | ||||
|  | ||||
|     private void initView() { | ||||
|         // 设置调试日志显示 | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|         if (appConfigs == null) { | ||||
|             appConfigs = new AppConfigs();  | ||||
|             AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|         } | ||||
|  | ||||
|         if (appConfigs.getSetupMode() == AppConfigs.SetupMode.WATCHOUTPUTINSTALLER) { | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton1)).setChecked(true); | ||||
|         } else if (appConfigs.getSetupMode() == AppConfigs.SetupMode.NEWAPKINFONEWAPKINFO) { | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton2)).setChecked(true); | ||||
|         }  | ||||
|  | ||||
|         NotificationUtil nu = new NotificationUtil(); | ||||
|         nu.createServiceNotificationChannel(MainActivity.this); | ||||
|  | ||||
|  | ||||
|         //Define shared preferences class | ||||
|         //shPrefs = new sharedPreferences(); | ||||
|  | ||||
|         mTextClock = findViewById(R.id.activitymainTextClock1); | ||||
|         mTextClock.setTimeZone("Asia/Shanghai"); | ||||
|         mTextClock.setFormat12Hour("yyyy/MM/dd HH:mm:ss"); | ||||
|  | ||||
|         mEditText = findViewById(R.id.activitymainEditText1); | ||||
|         //Add text from EditText to Shared Preferences | ||||
|         //mEditText.setText(shPrefs.getFilePath(MainActivity.this)); | ||||
|         mEditText.setText(appConfigs.getWatchingFilePath()); | ||||
|  | ||||
|         mListViewForScrollView = findViewById(R.id.activitymainListViewForScrollView1); | ||||
|         /*Map<String,Object> map1 =new HashMap<>(); | ||||
|          map1.put(MAP_NAME, "test1"); | ||||
|          mAdapterData.add(map1); | ||||
|          Map<String,Object> map2 =new HashMap<>(); | ||||
|          map2.put(MAP_NAME, "test2"); | ||||
|          mAdapterData.add(map2);*/ | ||||
|         // 绑定适配器与数据 | ||||
|         mSimpleAdapter = new SimpleAdapter(MainActivity.this, mAdapterData, R.layout.installitem | ||||
|                                            , new String[]{MAP_NAME} | ||||
|                                            , new int[]{R.id.installitemTextView1}); | ||||
|         mSimpleAdapter.setDropDownViewResource(R.layout.installitem); | ||||
|         mListViewForScrollView.setAdapter(mSimpleAdapter); | ||||
|  | ||||
|         mSwitch = findViewById(R.id.activitymainSwitch1); | ||||
|         //if (shPrefs.getIsLockFilePath(MainActivity.this)) { | ||||
|         if (appConfigs.isEnableService()) { | ||||
|             mSwitch.setChecked(true); | ||||
|             mEditText.setEnabled(false); | ||||
|             mEditText.setBackgroundColor(getColor(R.color.colorLock)); | ||||
|             szAPKFilePath = mEditText.getText().toString(); | ||||
|             startWatchingFile(); | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onOpenAPP(View view) { | ||||
|         if (mszInstalledPackageName.trim().equals("")) { | ||||
|             ToastUtils.show("Installed APP package name is null."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Intent intent = getPackageManager().getLaunchIntentForPackage(mszInstalledPackageName); | ||||
|         if (intent != null) { | ||||
|             startActivity(intent); | ||||
|         } else { | ||||
|             // 若没能获取到启动意图,可进行相应提示等操作,比如跳转到应用商店让用户下载该应用(示例) | ||||
|             Intent marketIntent = new Intent(Intent.ACTION_VIEW); | ||||
|             marketIntent.setData(Uri.parse("market://details?id=" + mszInstalledPackageName)); | ||||
|             startActivity(marketIntent); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onInstallAPK(View view) { | ||||
|         installAPK(); | ||||
|     } | ||||
|  | ||||
|     void installAPK() { | ||||
|         if (mszInstalledAPKFilePath.trim().equals("")) { | ||||
|             ToastUtils.show("Installed APK file path is null."); | ||||
|             return; | ||||
|         } | ||||
|         File file = new File(mszInstalledAPKFilePath); | ||||
|         Intent intent = new Intent(Intent.ACTION_VIEW); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本 | ||||
|             Uri apkUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file); | ||||
|             LogUtils.d(TAG, "Uri is : " + apkUri.toString()); | ||||
|             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | ||||
|             //intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); | ||||
|             intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); | ||||
|         } else { | ||||
|             intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); | ||||
|         } | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         this.startActivityForResult(intent, REQUEST_CODE_ON_INSTALL_COMPLETED); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|         //super.onActivityResult(requestCode, resultCode, data); | ||||
|         if (requestCode == REQUEST_CODE_ON_INSTALL_COMPLETED) { | ||||
|             // 根据resultCode等判断具体情况,这里简单示例显示一个普通吐司 | ||||
|             //Toast.makeText(this, "[ " + mszInstalledPackageName + " ]安装窗口已关闭啦", Toast.LENGTH_SHORT).show(); | ||||
|             //finish(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onLockPath(View view) { | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|  | ||||
|         Switch sw = (Switch)view; | ||||
|         if (sw.isChecked()) { | ||||
|             String szFilePath = mEditText.getText().toString(); | ||||
|  | ||||
|             // 设置空路径时退出 | ||||
|             // | ||||
|             if (szFilePath.trim().equals("")) { | ||||
|                 sw.setChecked(false); | ||||
|                 Toast.makeText(getApplication(), "监控路径为空。", Toast.LENGTH_SHORT).show(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // 设置监控功能 | ||||
|             // | ||||
|             File f = new File(szFilePath); | ||||
|             if (f != null && f.getParentFile() != null && f.getParentFile().exists()) { | ||||
|  | ||||
|                 //shPrefs.saveFilePath(MainActivity.this, mEditText.getText().toString()); | ||||
|                 appConfigs.setWatchingFilePath(mEditText.getText().toString()); | ||||
|                 //shPrefs.saveIsLockFilePath(MainActivity.this, true); | ||||
|                 appConfigs.setIsEnableService(true); | ||||
|                 mEditText.setEnabled(false); | ||||
|                 mEditText.setBackgroundColor(getColor(R.color.colorLock)); | ||||
|                 szAPKFilePath = mEditText.getText().toString(); | ||||
|                 startWatchingFile(); | ||||
|             } /*else { | ||||
|              if (mEditText.getText().toString().trim().equals("")) { | ||||
|              //shPrefs.saveFilePath(MainActivity.this, ""); | ||||
|              appConfigs.setWatchingFilePath(""); | ||||
|  | ||||
|              //shPrefs.saveIsLockFilePath(MainActivity.this, true); | ||||
|              appConfigs.setIsEnableService(true); | ||||
|  | ||||
|              mEditText.setEnabled(false); | ||||
|              mEditText.setBackgroundColor(getColor(R.color.colorLock)); | ||||
|              szAPKFilePath = ""; | ||||
|              } else { | ||||
|              sw.setChecked(false); | ||||
|              } | ||||
|              }*/ | ||||
|         } else { | ||||
|             //shPrefs.saveIsLockFilePath(MainActivity.this, false); | ||||
|             appConfigs.setIsEnableService(false); | ||||
|  | ||||
|             mEditText.setEnabled(true); | ||||
|             mEditText.setBackgroundColor(Color.TRANSPARENT); | ||||
|             stopWatchingFile(); | ||||
|  | ||||
|         } | ||||
|         AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|     } | ||||
|  | ||||
|     void stopWatchingFile() { | ||||
|         Intent intentService = new Intent(this, MainService.class); | ||||
|         stopService(intentService); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void startWatchingFile() { | ||||
|         LogUtils.d(TAG, "startWatchingFile()"); | ||||
|         Intent intentService = new Intent(MainActivity.this, MainService.class); | ||||
|         //intentService.putExtra(MainService.EXTRA_APKFILEPATH, szAPKFilePath); | ||||
|         startService(intentService); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      *Using class allows you to read data from Shared Preferences from other Activities | ||||
|      */ | ||||
|     /*static class sharedPreferences { | ||||
|  | ||||
|      // | ||||
|      //Save file path | ||||
|      // | ||||
|      public void saveFilePath(Activity activity, String _filePath) { | ||||
|      SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); | ||||
|      SharedPreferences.Editor editor = sharedPref.edit(); | ||||
|      editor.putString("_filePath", _filePath); | ||||
|      editor.apply(); | ||||
|      } | ||||
|  | ||||
|      // | ||||
|      //Read file path. | ||||
|      // | ||||
|      public String  getFilePath(Activity activity) { | ||||
|      SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); | ||||
|      return sharedPref.getString("_filePath", ""); | ||||
|      } | ||||
|  | ||||
|      // | ||||
|      //Set file path lock status. | ||||
|      // | ||||
|      public void saveIsLockFilePath(Activity activity, boolean isLockFilePath) { | ||||
|      SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); | ||||
|      SharedPreferences.Editor editor = sharedPref.edit(); | ||||
|      editor.putBoolean("isLockFilePath", isLockFilePath); | ||||
|      editor.apply(); | ||||
|      } | ||||
|  | ||||
|      // | ||||
|      //Read file path lock status. | ||||
|      // | ||||
|      public boolean getIsLockFilePath(Activity activity) { | ||||
|      SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); | ||||
|      return sharedPref.getBoolean("isLockFilePath", false); | ||||
|      } | ||||
|      }*/ | ||||
|  | ||||
|     public void onChangeSetupMode(View view) { | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|  | ||||
|         if (view.getId() == R.id.activitymainRadioButton1) { | ||||
|             appConfigs.setSetupMode(AppConfigs.SetupMode.WATCHOUTPUTINSTALLER); | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton2)).setChecked(false); | ||||
|         } else if (view.getId() == R.id.activitymainRadioButton2) { | ||||
|             appConfigs.setSetupMode(AppConfigs.SetupMode.NEWAPKINFONEWAPKINFO); | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton1)).setChecked(false); | ||||
|         } | ||||
|         AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,145 @@ | ||||
| package cc.winboll.studio.autoinstaller.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/27 17:36:01 | ||||
|  * @Describe 应用配置数据类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.utils.FileUtil; | ||||
| import java.io.IOException; | ||||
| import java.io.Serializable; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class AppConfigs implements Serializable { | ||||
|  | ||||
|     public static final String TAG = "AppConfigs"; | ||||
|  | ||||
|     // 安装模式 | ||||
|     public static enum SetupMode { | ||||
|         WATCHOUTPUTINSTALLER, // 本应用直接调用安装 | ||||
|         NEWAPKINFONEWAPKINFO  // 调用[应用信息查看器]打开应用包 | ||||
|         }; | ||||
|  | ||||
|     // 监控文件路径 | ||||
|     private String watchingFilePath = ""; | ||||
|  | ||||
|     // 是否启动服务 | ||||
|     private boolean isEnableService = false; | ||||
|  | ||||
|     // 安装工具模式 | ||||
|     private SetupMode setupMode = SetupMode.WATCHOUTPUTINSTALLER; | ||||
|  | ||||
|  | ||||
|     public void setWatchingFilePath(String watchingFilePath) { | ||||
|         this.watchingFilePath = watchingFilePath; | ||||
|     } | ||||
|  | ||||
|     public String getWatchingFilePath() { | ||||
|         return watchingFilePath; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnableService(boolean isEnableService) { | ||||
|         this.isEnableService = isEnableService; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableService() { | ||||
|         return isEnableService; | ||||
|     } | ||||
|  | ||||
|     public void setSetupMode(SetupMode setupMode) { | ||||
|         this.setupMode = setupMode; | ||||
|     } | ||||
|  | ||||
|     public SetupMode getSetupMode() { | ||||
|         return setupMode; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringWriter stringWriter = new StringWriter(); | ||||
|         JsonWriter writer = new | ||||
|             JsonWriter(stringWriter); | ||||
|         try { | ||||
|             // 开始 JSON 对象 | ||||
|             writer.beginObject(); | ||||
|  | ||||
|             // 写入键值对 | ||||
|             writer.name("watchingFilePath").value(this.watchingFilePath); | ||||
|             writer.name("isEnableService").value(this.isEnableService); | ||||
|             writer.name("setupMode").value(this.setupMode.ordinal()); | ||||
|  | ||||
|             // 结束 JSON 对象 | ||||
|             writer.endObject(); | ||||
|             return stringWriter.toString(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         // 获取 JSON 字符串 | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static AppConfigs parseAppConfigs(String szAppConfigs) { | ||||
|         AppConfigs appConfigs = new AppConfigs(); | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringReader stringReader = new StringReader(szAppConfigs); | ||||
|         JsonReader jsonReader = new | ||||
|             JsonReader(stringReader); | ||||
|         try { | ||||
|             // 开始 JSON 对象 | ||||
|             jsonReader.beginObject(); | ||||
|  | ||||
|             // 写入键值对 | ||||
|             while (jsonReader.hasNext()) { | ||||
|                 String name = jsonReader.nextName(); | ||||
|                 if (name.equals("watchingFilePath")) { | ||||
|                     appConfigs.setWatchingFilePath(jsonReader.nextString()); | ||||
|                 } else if (name.equals("isEnableService")) { | ||||
|                     appConfigs.setIsEnableService(jsonReader.nextBoolean()); | ||||
|                 } else if (name.equals("setupMode")) { | ||||
|                     appConfigs.setSetupMode(SetupMode.values()[jsonReader.nextInt()]); | ||||
|                 } else { | ||||
|                     jsonReader.skipValue(); | ||||
|                 } | ||||
|             } | ||||
|             // 结束 JSON 对象 | ||||
|             jsonReader.endObject(); | ||||
|             return appConfigs; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         // 获取 JSON 字符串 | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     static String getDataPath(Context context) { | ||||
|         return context.getExternalFilesDir(TAG) + "/" + TAG + ".json"; | ||||
|     } | ||||
|  | ||||
|     public static AppConfigs loadAppConfigs(Context context) { | ||||
|         AppConfigs appConfigs = null; | ||||
|         try { | ||||
|             String szJson = FileUtil.readFile(getDataPath(context)); | ||||
|             appConfigs = AppConfigs.parseAppConfigs(szJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return appConfigs; | ||||
|     } | ||||
|  | ||||
|     public static void saveAppConfigs(Context context, AppConfigs appConfigs) { | ||||
|         try { | ||||
|             //LogUtils.d(TAG, "appConfigs is : " + appConfigs.toString()); | ||||
|             String szJson = appConfigs.toString(); | ||||
|             FileUtil.writeFile(getDataPath(context), szJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| package cc.winboll.studio.autoinstaller.receivers; | ||||
|  | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/06 13:19:38 | ||||
|  * @Describe 应用消息接收类 | ||||
|  */ | ||||
| public class MainReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "MainReceiver"; | ||||
|  | ||||
|     static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_BOOT_COMPLETED)) { | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(context); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 Intent intentService = new Intent(context, MainService.class); | ||||
|                 //intentService.putExtra(MainService.EXTRA_APKFILEPATH, appConfigs.getWatchingFilePath()); | ||||
|                 if (Build.VERSION.SDK_INT >= 26) { | ||||
|                     context.startForegroundService(intentService); | ||||
|                 } else { | ||||
|                     context.startService(intentService); | ||||
|                 } | ||||
|                 LogUtils.i(TAG, "System Boot And Start MainService Completed!"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,110 @@ | ||||
| package cc.winboll.studio.autoinstaller.services; | ||||
|  | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.utils.ServiceUtil; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/27 20:16:00 | ||||
|  * @Describe MainService 守护进程服务 | ||||
|  */ | ||||
| public class AssistantService extends Service { | ||||
|  | ||||
|     public static final String TAG = "AssistantService"; | ||||
|  | ||||
|     //MyBinder mMyBinder; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     volatile boolean mIsThreadAlive; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         //return mMyBinder; | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         //LogUtils.d(TAG, "call onCreate()"); | ||||
|         super.onCreate(); | ||||
|  | ||||
|         //mMyBinder = new MyBinder(); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         // 设置运行参数 | ||||
|         mIsThreadAlive = false; | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         //LogUtils.d(TAG, "call onStartCommand(...)"); | ||||
|         run(); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|         return appConfigs.isEnableService() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     /*class MyBinder extends IMyAidlInterface.Stub { | ||||
|      @Override | ||||
|      public String getServiceName() { | ||||
|      return AssistantService.class.getSimpleName(); | ||||
|      } | ||||
|      }*/ | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //LogUtils.d(TAG, "call onDestroy()"); | ||||
|         mIsThreadAlive = false; | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void run() { | ||||
|         //LogUtils.d(TAG, "call run()"); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|         if (appConfigs.isEnableService()) { | ||||
|             if (mIsThreadAlive == false) { | ||||
|                 // 设置运行状态 | ||||
|                 mIsThreadAlive = true; | ||||
|                 // 唤醒和绑定主进程 | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定主进程 | ||||
|     // | ||||
|     void wakeupAndBindMain() { | ||||
|         if (ServiceUtil.isServiceAlive(getApplicationContext(), MainService.class.getName()) == false) { | ||||
|             //LogUtils.d(TAG, "wakeupAndBindMain() Wakeup... ControlCenterService"); | ||||
|             startForegroundService(new Intent(AssistantService.this, MainService.class)); | ||||
|         } | ||||
|         //LogUtils.d(TAG, "wakeupAndBindMain() Bind... ControlCenterService"); | ||||
|         bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             //LogUtils.d(TAG, "call onServiceDisconnected(...)"); | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,248 @@ | ||||
| package cc.winboll.studio.autoinstaller.services; | ||||
|  | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Handler; | ||||
| import android.os.IBinder; | ||||
| import android.os.Message; | ||||
| import android.widget.Toast; | ||||
| import androidx.core.content.FileProvider; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.autoinstaller.FileListener; | ||||
| import cc.winboll.studio.autoinstaller.MainActivity; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.AssistantService; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.autoinstaller.utils.NotificationUtil; | ||||
| import cc.winboll.studio.autoinstaller.utils.PackageUtil; | ||||
| import cc.winboll.studio.autoinstaller.utils.ServiceUtil; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.File; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class MainService extends Service { | ||||
|  | ||||
|     public static String TAG = "MainService"; | ||||
|  | ||||
|     private static boolean _mIsServiceAlive; | ||||
|     //String mszAPKFilePath; | ||||
|     //String mszAPKFileName; | ||||
|     FileListener mFileListener; | ||||
|     public static final String EXTRA_APKFILEPATH = "EXTRA_APKFILEPATH"; | ||||
| 	final static int MSG_INSTALL_APK = 0; | ||||
|     Handler mHandler; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     MainActivity mInstallCompletedFollowUpActivity; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|         _mIsServiceAlive = false; | ||||
|         mHandler = new MyHandler(MainService.this); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     private void run() { | ||||
|  | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|         if (appConfigs.isEnableService()) { | ||||
|             if (_mIsServiceAlive == false) { | ||||
|                 // 设置运行状态 | ||||
|                 _mIsServiceAlive = true; | ||||
|  | ||||
|                 // 显示前台通知栏 | ||||
|                 NotificationUtil nu = new NotificationUtil(); | ||||
|                 nu.sendForegroundNotification(MainService.this); | ||||
|  | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|  | ||||
|                 startWatchingFile(appConfigs.getWatchingFilePath()); | ||||
|  | ||||
|                 LogUtils.d(TAG, "running..."); | ||||
|  | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "_mIsServiceAlive is " + Boolean.toString(_mIsServiceAlive)); | ||||
|  | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         if (mFileListener != null) { | ||||
|             mFileListener.stopWatching(); | ||||
|             mFileListener = null; | ||||
|             LogUtils.d(TAG, "stopWatching"); | ||||
|  | ||||
|         } | ||||
|         _mIsServiceAlive = false; | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand"); | ||||
|  | ||||
|         run(); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|  | ||||
|         return appConfigs.isEnableService() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     private class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定守护进程 | ||||
|     // | ||||
|     void wakeupAndBindAssistant() { | ||||
|         if (ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) { | ||||
|             startService(new Intent(MainService.this, AssistantService.class)); | ||||
|             //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService"); | ||||
|             bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void startWatchingFile(String szAPKFilePath) { | ||||
|         try { | ||||
|             File fTemp = new File(szAPKFilePath); | ||||
|             final File fParentDir = fTemp.getParentFile(); | ||||
|             final String szAPKFileName = fTemp.getName(); | ||||
|             if (fParentDir.exists()) { | ||||
|                 mFileListener = new FileListener(fParentDir.toString()); | ||||
|  | ||||
|                 mFileListener.setEventCallback(new FileListener.EventCallback() { | ||||
|  | ||||
|                         @Override | ||||
|                         public void onEvent(String path) { | ||||
|                             //LogUtils.d(TAG, "path : " + path); | ||||
|                             File fTemo = new File(fParentDir, path); | ||||
|                             if (fTemo.getName().equals(szAPKFileName)) { | ||||
|                                 Message message = mHandler.obtainMessage(MSG_INSTALL_APK); | ||||
|                                 message.obj = fTemo.toString(); | ||||
|                                 mHandler.sendMessage(message); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|  | ||||
|                     }); | ||||
|                 mFileListener.startWatching(); | ||||
|                 ToastUtils.show("Start watching."); | ||||
|             } else { | ||||
|                 // 父级文件夹不存在,就提示用户 | ||||
|                 Toast.makeText(getApplication(), fParentDir.toString() + " no exist.", Toast.LENGTH_SHORT).show(); | ||||
|             } | ||||
|  | ||||
|         } catch (Exception e) { | ||||
|             Toast.makeText(getApplication(), szAPKFilePath.toString() + " watching failed.", Toast.LENGTH_SHORT).show(); | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 调用[应用信息查看器]打开应用包 | ||||
|     // | ||||
|     private void installAPK(String szAPKFilePath) { | ||||
|         long nTimeNow = System.currentTimeMillis(); | ||||
|         /*SimpleDateFormat dateFormat = new SimpleDateFormat( | ||||
|          "yyyy-MM-dd HH:mm:ss", Locale.getDefault()); | ||||
|          Date d = new Date(nTimeNow); | ||||
|          Map<String,Object> map =new HashMap<>(); | ||||
|          map.put(MAP_NAME, dateFormat.format(d)); | ||||
|          mAdapterData.add(0, map); | ||||
|          mSimpleAdapter.notifyDataSetChanged(); | ||||
|          LogUtils.d(TAG, "Start install APK");*/ | ||||
|  | ||||
|         File file = new File(szAPKFilePath); | ||||
|         LogUtils.i(TAG, "New APK File is : " + szAPKFilePath); | ||||
|         Intent intent = new Intent(Intent.ACTION_VIEW); | ||||
|         intent.setClassName("com.kk.xx.newapkinfo", "sk.styk.martin.apkanalyzer.ui.activity.appdetail.oninstall.OnInstallAppDetailActivity"); | ||||
|  | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本 | ||||
|             Uri apkUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file); | ||||
|             LogUtils.d(TAG, "Uri is : " + apkUri.toString()); | ||||
|             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | ||||
|             //intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); | ||||
|             intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); | ||||
|         } else { | ||||
|             intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); | ||||
|         } | ||||
|         this.startActivity(intent); | ||||
|         LogUtils.i(TAG, "Start Install Activity."); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 直接调用系统安装工具进行安装 | ||||
|     // | ||||
|     void installAPK2(String szAPKFilePath) { | ||||
|         LogUtils.d(TAG, "installAPK2()"); | ||||
|         Intent intent = new Intent(this, MainActivity.class); | ||||
|         intent.setAction(MainActivity.ACTION_NEW_INSTALLTASK); | ||||
|         intent.putExtra(MainActivity.EXTRA_INSTALLED_PACKAGENAME, PackageUtil.getPackageNameFromApk(this, szAPKFilePath)); | ||||
|         intent.putExtra(MainActivity.EXTRA_INSTALLED_APKFILEPATH, szAPKFilePath); | ||||
|         // Intent.ACTION_VIEW); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         this.startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     //  | ||||
|     // | ||||
|     static class MyHandler extends Handler { | ||||
|         WeakReference<MainService> weakReference;   | ||||
|         MyHandler(MainService service) {   | ||||
|             weakReference = new WeakReference<MainService>(service);   | ||||
|         } | ||||
|         public void handleMessage(Message message) { | ||||
|             MainService theActivity = weakReference.get(); | ||||
|             switch (message.what) { | ||||
|                 case MSG_INSTALL_APK: | ||||
|                     { | ||||
|                         AppConfigs appConfigs = AppConfigs.loadAppConfigs(theActivity); | ||||
|                         if (appConfigs.getSetupMode() == AppConfigs.SetupMode.WATCHOUTPUTINSTALLER) { | ||||
|                             theActivity.installAPK2((String)message.obj); | ||||
|                         } else if (appConfigs.getSetupMode() == AppConfigs.SetupMode.NEWAPKINFONEWAPKINFO) { | ||||
|                             theActivity.installAPK((String)message.obj); | ||||
|                         } | ||||
|                         break; | ||||
|                     } | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             super.handleMessage(message); | ||||
|         } | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/27 17:56:31 | ||||
|  * @Describe 文件管理类 | ||||
|  */ | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.nio.charset.StandardCharsets; | ||||
|  | ||||
| public class FileUtil { | ||||
|      | ||||
|     public static final String TAG = "FileUtil"; | ||||
|      | ||||
|     // | ||||
|     // 把字符串写入文件,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static void writeFile(String filePath, String content) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         FileOutputStream outputStream = new FileOutputStream(file); | ||||
|         OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); | ||||
|         writer.write(content); | ||||
|         writer.close(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取文件到字符串,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static String readFile(String filePath) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         FileInputStream inputStream = new FileInputStream(file); | ||||
|         InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); | ||||
|         StringBuilder content = new StringBuilder(); | ||||
|         int character; | ||||
|         while ((character = reader.read()) != -1) { | ||||
|             content.append((char) character); | ||||
|         } | ||||
|         reader.close(); | ||||
|         return content.toString(); | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,82 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationChannel; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Color; | ||||
| import android.media.RingtoneManager; | ||||
| import android.os.Build; | ||||
| import android.util.Log; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.autoinstaller.MainActivity; | ||||
| import cc.winboll.studio.autoinstaller.R; | ||||
|  | ||||
| public class NotificationUtil { | ||||
|  | ||||
|     static final String TAG = "NotificationUtil"; | ||||
|     static final String szServiceChannelID = "0"; | ||||
|     static int mNumSendForegroundNotification = 10000; | ||||
|  | ||||
|     public NotificationManager createServiceNotificationChannel(Context context) { | ||||
|         //创建通知渠道ID | ||||
|         String channelId = szServiceChannelID; | ||||
|         //创建通知渠道名称 | ||||
|         String channelName = "Service Message"; | ||||
|         //创建通知渠道重要性 | ||||
|         int importance = NotificationManager.IMPORTANCE_MIN; | ||||
|         NotificationChannel channel = new NotificationChannel(channelId, channelName, importance); | ||||
|         channel.setSound(null, null); | ||||
|         NotificationManager notificationManager = (NotificationManager) context.getSystemService( | ||||
|             Context.NOTIFICATION_SERVICE); | ||||
|         notificationManager.createNotificationChannel(channel); | ||||
|         return notificationManager; | ||||
|     } | ||||
|  | ||||
|     // 创建通知 | ||||
|     // | ||||
|     public void sendForegroundNotification(MainService service) { | ||||
|         //创建Notification,传入Context和channelId | ||||
|         Intent intent = new Intent();//这个intent会传给目标,可以使用getIntent来获取 | ||||
|         intent.setClass(service, MainActivity.class); | ||||
|  | ||||
|         //这里放一个count用来区分每一个通知 | ||||
|         //intent.putExtra("intent", "intent--->" + count);//这里设置一个数据,带过去 | ||||
|  | ||||
|         //参数1:context 上下文对象 | ||||
|         //参数2:发送者私有的请求码(Private request code for the sender) | ||||
|         //参数3:intent 意图对象 | ||||
|         //参数4:必须为FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT,中的一个 | ||||
|         PendingIntent mForegroundPendingIntent = PendingIntent.getActivity(service, mNumSendForegroundNotification, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT); | ||||
|  | ||||
|         Notification mForegroundNotification = new Notification.Builder(service, szServiceChannelID) | ||||
|             .setAutoCancel(true) | ||||
|             .setContentTitle(service.getString(R.string.app_name)) | ||||
|             .setContentText(service.TAG + " is started.") | ||||
|             .setWhen(System.currentTimeMillis()) | ||||
|             .setSmallIcon(R.drawable.ic_launcher) | ||||
|             //设置红色 | ||||
|             .setColor(Color.parseColor("#F00606")) | ||||
|             .setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher)) | ||||
|             .setContentIntent(mForegroundPendingIntent) | ||||
|             .build(); | ||||
|  | ||||
|  | ||||
|         /*RemoteViews mrvForegroundNotificationView = new RemoteViews(service.getPackageName(), R.layout.remoteview); | ||||
|         mrvForegroundNotificationView.setTextViewText(R.id.remoteviewTextView1, notificationMessage.getTitle()); | ||||
|         mrvForegroundNotificationView.setTextViewText(R.id.remoteviewTextView2, notificationMessage.getContent()); | ||||
|         mrvForegroundNotificationView.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher); | ||||
|         mForegroundNotification.contentView = mrvForegroundNotificationView; | ||||
|         mForegroundNotification.bigContentView = mrvForegroundNotificationView; | ||||
|         */ | ||||
|  | ||||
|         service.startForeground(mNumSendForegroundNotification, mForegroundNotification); | ||||
|  | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -0,0 +1,30 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/12/11 06:28:50 | ||||
|  * @Describe 一个获取安卓APK安装文件的应用包名的函数 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class PackageUtil { | ||||
|  | ||||
|     public static final String TAG = "PackageUtil"; | ||||
|  | ||||
|     public static String getPackageNameFromApk(Context context, String apkFilePath) { | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         PackageInfo packageInfo = null; | ||||
|         try { | ||||
|             packageInfo = packageManager.getPackageArchiveInfo(apkFilePath, 0); | ||||
|             if (packageInfo != null) { | ||||
|                 return packageInfo.packageName; | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/27 20:20:03 | ||||
|  * @Describe 服务类工具 | ||||
|  */ | ||||
| import android.app.ActivityManager; | ||||
| import android.content.Context; | ||||
| import java.util.List; | ||||
|  | ||||
| public class ServiceUtil { | ||||
|  | ||||
|     public final static String TAG = "ServiceUtil"; | ||||
|  | ||||
|     public static boolean isServiceAlive(Context context, String szServiceName) { | ||||
|         // 获取Activity管理者对象 | ||||
|         ActivityManager manager = (ActivityManager) context | ||||
|             .getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         // 获取正在运行的服务(此处设置最多取1000个) | ||||
|         List<ActivityManager.RunningServiceInfo> runningServices = manager | ||||
|             .getRunningServices(1000); | ||||
|         if (runningServices.size() <= 0) { | ||||
|             return false; | ||||
|         } | ||||
|         // 遍历,若存在名字和传入的serviceName的一致则说明存在 | ||||
|         for (ActivityManager.RunningServiceInfo runningServiceInfo : runningServices) { | ||||
|             if (runningServiceInfo.service.getClassName().equals(szServiceName)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,77 @@ | ||||
| package cc.winboll.studio.autoinstaller.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
|  | ||||
| public class ListViewForScrollView extends ListView { | ||||
|     static int nMaxWidth = 0; | ||||
|  | ||||
|     public ListViewForScrollView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public ListViewForScrollView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public ListViewForScrollView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重写onMeasure方法,重新计算高度,达到使ListView适应ScrollView的效果 | ||||
|      * | ||||
|      * @param widthMeasureSpec  宽度测量规则 | ||||
|      * @param heightMeasureSpec 高度测量规则 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|  | ||||
|         /* | ||||
|          // 子控件TextView不换行显示 | ||||
|          ListAdapter listAdapter = this.getAdapter();   | ||||
|          if (listAdapter == null) {  | ||||
|          return;  | ||||
|          } | ||||
|          int maxWidth = 0; | ||||
|          for (int i = 0; i < listAdapter.getCount(); i++) {  | ||||
|          View listItem = listAdapter.getView(i, null, this); | ||||
|          View cb = listItem.findViewById(R.id.listviewfiledataCheckBox1); | ||||
|          View iv = listItem.findViewById(R.id.listviewfiledataImageView1); | ||||
|          View tv = listItem.findViewById(R.id.listviewfiledataTextView1); | ||||
|  | ||||
|          cb.measure(0,0); | ||||
|          iv.measure(0,0); | ||||
|          tv.measure(0,0); | ||||
|  | ||||
|          //listItem.measure(0, 0); | ||||
|          //int width = listItem.getMeasuredWidth(); | ||||
|          int width = cb.getMeasuredWidth() + iv.getMeasuredWidth()+ tv.getMeasuredWidth(); | ||||
|          if(width>maxWidth) maxWidth = width; | ||||
|          } | ||||
|          int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|          int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); | ||||
|          super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); | ||||
|          */ | ||||
|  | ||||
|         // 子控件TextView换行显示 | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|  | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
|  | ||||
| } | ||||
|      | ||||
|      | ||||
|      | ||||
|  | ||||
							
								
								
									
										11
									
								
								autoinstaller/src/main/res/drawable/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								autoinstaller/src/main/res/drawable/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:clickable="true"> | ||||
|     <item android:drawable="@drawable/ic_launcher_background"/>  | ||||
|     <item  | ||||
|         android:left="15dp"  | ||||
|         android:top="15dp"  | ||||
|         android:right="15dp"  | ||||
|         android:bottom="15dp" | ||||
|         android:drawable="@drawable/ic_launcher_foreground"/> | ||||
| </layer-list> | ||||
							
								
								
									
										171
									
								
								autoinstaller/src/main/res/drawable/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								autoinstaller/src/main/res/drawable/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path | ||||
|         android:fillColor="#FF009DCB" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
| </vector> | ||||
|  | ||||
| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/> | ||||
| </vector> | ||||
|  | ||||
							
								
								
									
										11
									
								
								autoinstaller/src/main/res/drawable/ic_winboll.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								autoinstaller/src/main/res/drawable/ic_winboll.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:clickable="true"> | ||||
|     <item android:drawable="@drawable/ic_launcher_background"/>  | ||||
|     <item  | ||||
|         android:left="15dp"  | ||||
|         android:top="15dp"  | ||||
|         android:right="15dp"  | ||||
|         android:bottom="15dp" | ||||
|         android:drawable="@drawable/ic_launcher_foreground"/> | ||||
| </layer-list> | ||||
							
								
								
									
										10
									
								
								autoinstaller/src/main/res/drawable/shape_gradient.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								autoinstaller/src/main/res/drawable/shape_gradient.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <gradient | ||||
|         android:angle="180" | ||||
|         android:endColor="@color/purple_500" | ||||
|         android:startColor="@color/purple_200" | ||||
|         android:type="linear" /> | ||||
|  | ||||
|     <corners android:radius="10dp" /> | ||||
| </shape> | ||||
| @@ -0,0 +1,13 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:gravity="center"> | ||||
|  | ||||
| 	 | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										142
									
								
								autoinstaller/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								autoinstaller/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	xmlns:tools="http://schemas.android.com/tools" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	tools:context=".MainActivity" | ||||
| 	android:orientation="vertical"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="center_horizontal"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Watching File :"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="horizontal" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="center_vertical"> | ||||
|  | ||||
| 			<EditText | ||||
| 				android:layout_width="0dp" | ||||
| 				android:ems="10" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:layout_weight="1.0" | ||||
| 				android:id="@+id/activitymainEditText1"/> | ||||
|  | ||||
| 			<Switch | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:onClick="onLockPath" | ||||
| 				android:id="@+id/activitymainSwitch1"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="horizontal" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<RadioButton | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:id="@+id/activitymainRadioButton1" | ||||
| 				android:text="直接安装" | ||||
| 				android:onClick="onChangeSetupMode"/> | ||||
|  | ||||
| 			<RadioButton | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:id="@+id/activitymainRadioButton2" | ||||
| 				android:text="用[应用信息查看器]打开" | ||||
| 				android:onClick="onChangeSetupMode"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Times Now :"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="horizontal" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="center_vertical"> | ||||
|  | ||||
| 			<AnalogClock | ||||
| 				android:layout_width="40dp" | ||||
| 				android:layout_height="40dp"/> | ||||
|  | ||||
| 			<TextClock | ||||
| 				android:textSize="20sp" | ||||
| 				android:id="@+id/activitymainTextClock1" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:gravity="center"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="Installed Times :"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:gravity="center" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<ScrollView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="match_parent"> | ||||
|  | ||||
| 			<cc.winboll.studio.autoinstaller.views.ListViewForScrollView | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="match_parent" | ||||
| 				android:id="@+id/activitymainListViewForScrollView1"/> | ||||
|  | ||||
| 		</ScrollView> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="right"> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="安装应用包" | ||||
| 			android:onClick="onInstallAPK"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="打开应用" | ||||
| 			android:onClick="onOpenAPP"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<cc.winboll.studio.shared.log.LogView | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="200dp" | ||||
| 		android:id="@+id/logview"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										15
									
								
								autoinstaller/src/main/res/layout/installitem.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								autoinstaller/src/main/res/layout/installitem.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:layout_width="fill_parent" | ||||
| 	android:layout_height="fill_parent" | ||||
| 	android:orientation="vertical"> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="Text" | ||||
| 		android:id="@+id/installitemTextView1"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										38
									
								
								autoinstaller/src/main/res/layout/toast_custom_view.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								autoinstaller/src/main/res/layout/toast_custom_view.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:layout_width="wrap_content" | ||||
| 	android:layout_height="wrap_content" | ||||
| 	android:background="@drawable/shape_gradient" | ||||
| 	android:gravity="center" | ||||
| 	android:orientation="vertical" | ||||
| 	android:padding="10dp"> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="@string/app_name" | ||||
| 		android:textStyle="bold"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content"> | ||||
|  | ||||
| 		<ImageView | ||||
| 			android:layout_width="40dp" | ||||
| 			android:layout_height="40dp" | ||||
| 			android:src="@drawable/ic_winboll"/> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:id="@android:id/message" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:layout_margin="10dp" | ||||
| 			android:textColor="#FFFFFFFF" | ||||
| 			android:textSize="16sp"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										9
									
								
								autoinstaller/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								autoinstaller/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <declare-styleable name="LogView"> | ||||
|         <attr name="tagList" format="string" /> | ||||
|         <attr name="levelDefault" format="string" /> | ||||
|         <attr name="textColor" format="color" /> | ||||
|         <attr name="textIsSelectable" format="boolean" /> | ||||
|     </declare-styleable> | ||||
| </resources> | ||||
							
								
								
									
										11
									
								
								autoinstaller/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								autoinstaller/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="purple_200">#FFBB86FC</color> | ||||
|     <color name="purple_500">#FF6200EE</color> | ||||
|     <color name="purple_700">#FF3700B3</color> | ||||
|     <color name="teal_200">#FF03DAC5</color> | ||||
|     <color name="teal_700">#FF018786</color> | ||||
|     <color name="black">#FF000000</color> | ||||
|     <color name="white">#FFFFFFFF</color> | ||||
|     <color name="colorLock">#E8E8E8</color> | ||||
| </resources> | ||||
							
								
								
									
										3
									
								
								autoinstaller/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								autoinstaller/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <resources> | ||||
|     <string name="app_name">AutoInstaller</string> | ||||
| </resources> | ||||
							
								
								
									
										14
									
								
								autoinstaller/src/main/res/values/themes.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								autoinstaller/src/main/res/values/themes.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <resources xmlns:tools="http://schemas.android.com/tools"> | ||||
|     <!-- Base application theme. --> | ||||
|     <style name="Theme.Application" parent="android:Theme.Material.Light.DarkActionBar"> | ||||
|         <!-- Primary brand color. --> | ||||
|         <item name="android:colorPrimary">@color/purple_500</item> | ||||
|          | ||||
|         <!-- Secondary brand color. --> | ||||
|         <item name="android:colorSecondary">@color/teal_200</item> | ||||
|          | ||||
|         <!-- Status bar color. --> | ||||
|         <item name="android:statusBarColor" tools:targetApi="l">@color/purple_700</item> | ||||
|         <!-- Customize your theme here. --> | ||||
|     </style> | ||||
| </resources> | ||||
							
								
								
									
										26
									
								
								autoinstaller/src/main/res/xml/provider_paths.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								autoinstaller/src/main/res/xml/provider_paths.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <paths> | ||||
|     <external-path | ||||
|         name="external_storage_root" | ||||
|         path="." /> | ||||
|     <files-path | ||||
|         name="files-path" | ||||
|         path="." /> | ||||
|     <cache-path | ||||
|         name="cache-path" | ||||
|         path="." /> | ||||
|     <!--/storage/emulated/0/Android/data/...--> | ||||
|     <external-files-path | ||||
|         name="external_file_path" | ||||
|         path="." /> | ||||
|     <!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录--> | ||||
|     <external-cache-path | ||||
|         name="external_cache_path" | ||||
|         path="." /> | ||||
|     <!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录,否则微信分身保存的图片,就会导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/999/tencent/MicroMsg/WeiXin/export1544062754693.jpg,在小米6的手机上微信分身有这个crash,华为没有 | ||||
|     --> | ||||
|     <root-path | ||||
|         name="root-path" | ||||
|         path="" /> | ||||
| </paths> | ||||
|  | ||||
							
								
								
									
										22
									
								
								autoinstaller/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								autoinstaller/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <provider | ||||
|             android:name="androidx.core.content.FileProvider" | ||||
|             android:authorities="cc.winboll.studio.autoinstaller.fileprovider" | ||||
|             android:exported="false" | ||||
|             android:grantUriPermissions="true"> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.support.FILE_PROVIDER_PATHS" | ||||
|                 android:resource="@xml/provider_paths"/> | ||||
|  | ||||
|         </provider> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								autoinstaller/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								autoinstaller/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|  | ||||
| </resources> | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen