diff --git a/README.md b/README.md index 76612d14a..ee0c8f325 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,24 @@ Import and build the project in Android Studio(__with Instant Run disabled__). T - `YAHFA`. This is the YAHFA hook module. - `demoHookPlugin`. This is a demo hook plugin which compiles to an APK. -After building the APKs, push the `demoHookPlugin` APK to device in folder `/sdcard/io.virtualhook/` and run the main application. All plugin APKs in `/sdcard/io.virtualhook` would be applied to applications running in VirtualHook. +## Usage + +- Write and build a hook plugin APK. You can take a look at the [demoHookPlugin](https://github.com/rk700/VirtualHook/tree/master/VirtualApp/app/src/main/res/drawable-xxhdpi/ic_extension_black_24dp.png) module for reference. __Don't forget to put following meta-data in AndroidManifest.xml:__ + +```xml + + + +``` -Please refer to [demoHookPlugin](https://github.com/rk700/VirtualHook/tree/master/VirtualApp/demoHookPlugin) for more details. +- Push the plugin APK to sdcard +- Run VirtualHook and click the `Add` button +- Swipe to the 'APPS IN SDCARD' page. Then select and add hook plugins which are displayed with an icon ![](VirtualApp/app/src/main/res/drawable-xxhdpi/ic_extension_black_24dp.png) +- Add and run non-plugin apps ## Hooking Native Methods diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java b/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java index 3b9285c73..80b7bd8f2 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java @@ -410,7 +410,7 @@ public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder cu AppData data = mLaunchpadAdapter.getList().get(target.getAdapterPosition()); return data.canReorder(); } catch (IndexOutOfBoundsException e) { - e.printStackTrace(); +// e.printStackTrace(); } return false; } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java b/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java index 89b016a3f..139a721eb 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java @@ -87,7 +87,7 @@ class AddResult { VUiKit.defer().when(() -> { InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0); addResult.justEnableHidden = installedAppInfo != null; - if (addResult.justEnableHidden) { + if (addResult.justEnableHidden && !info.isHook) { int[] userIds = installedAppInfo.getInstalledUsers(); int nextUserId = userIds.length; /* diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/ListAppFragment.java b/VirtualApp/app/src/main/java/io/virtualapp/home/ListAppFragment.java index 05f3e63c7..9398b02c7 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/ListAppFragment.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/ListAppFragment.java @@ -106,7 +106,7 @@ public boolean isSelectable(int position) { ArrayList dataList = new ArrayList(selectedIndices.length); for (int index : selectedIndices) { AppInfo info = mAdapter.getItem(index); - dataList.add(new AppInfoLite(info.packageName, info.path, info.fastOpen)); + dataList.add(new AppInfoLite(info.packageName, info.path, info.fastOpen, info.isHook)); } Intent data = new Intent(); data.putParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST, dataList); diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/AppPagerAdapter.java b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/AppPagerAdapter.java index 1bfffd67d..eff4cebfc 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/AppPagerAdapter.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/AppPagerAdapter.java @@ -38,7 +38,7 @@ public AppPagerAdapter(FragmentManager fm) { File dir = Reflect.on(volume).call("getPathFile").get(); String label = Reflect.on(volume).call("getUserLabel").get(); if (dir.listFiles() != null) { - titles.add(label); + titles.add("Apps in "+label); dirs.add(dir); } } @@ -46,7 +46,7 @@ public AppPagerAdapter(FragmentManager fm) { // Fallback: only support the default storage sources File storageFir = Environment.getExternalStorageDirectory(); if (storageFir.list() != null) { - titles.add("Ghost Installation"); + titles.add("Apps in sdcard"); dirs.add(storageFir); } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/CloneAppListAdapter.java b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/CloneAppListAdapter.java index 9f78f6916..75be21742 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/CloneAppListAdapter.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/CloneAppListAdapter.java @@ -82,6 +82,12 @@ public void onBindViewHolder(ViewHolder holder, int position) { } else { holder.labelView.setVisibility(View.INVISIBLE); } + if(info.isHook) { + holder.isHookIcon.setVisibility(View.VISIBLE); + } + else { + holder.isHookIcon.setVisibility(View.INVISIBLE); + } holder.itemView.setOnClickListener(v -> { mItemEventListener.onItemClick(info, position); @@ -127,6 +133,7 @@ class ViewHolder extends RecyclerView.ViewHolder { private TextView nameView; private ImageView appCheckView; private LabelView labelView; + ImageView isHookIcon; ViewHolder(View itemView) { super(itemView); @@ -135,6 +142,7 @@ class ViewHolder extends RecyclerView.ViewHolder { nameView = (TextView) itemView.findViewById(R.id.item_app_name); appCheckView = (ImageView) itemView.findViewById(R.id.item_app_checked); labelView = (LabelView) itemView.findViewById(R.id.item_app_clone_count); + isHookIcon = (ImageView)itemView.findViewById(R.id.item_app_ishook); } } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/LaunchpadAdapter.java b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/LaunchpadAdapter.java index 16ddeebce..0f387475c 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/LaunchpadAdapter.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/adapters/LaunchpadAdapter.java @@ -6,6 +6,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import java.util.List; @@ -59,11 +60,18 @@ public void onBindViewHolder(ViewHolder holder, int position) { holder.color = getColor(position); holder.iconView.setImageDrawable(data.getIcon()); holder.nameView.setText(data.getName()); - if (data.isFirstOpen() && !data.isLoading()) { - holder.firstOpenDot.setVisibility(View.VISIBLE); - } else { - holder.firstOpenDot.setVisibility(View.INVISIBLE); + if(!data.isHook()) { + if (data.isFirstOpen() && !data.isLoading()) { + holder.firstOpenDot.setVisibility(View.VISIBLE); + } else { + holder.firstOpenDot.setVisibility(View.INVISIBLE); + } + holder.isHookIcon.setVisibility(View.INVISIBLE); } + else{ + holder.isHookIcon.setVisibility(View.VISIBLE); + } + holder.itemView.setBackgroundColor(holder.color); holder.itemView.setOnClickListener(v -> { if (mAppClickListener != null) { @@ -172,13 +180,15 @@ public class ViewHolder extends RecyclerView.ViewHolder { TextView nameView; LabelView spaceLabelView; View firstOpenDot; + ImageView isHookIcon; ViewHolder(View itemView) { super(itemView); - iconView = (LauncherIconView) itemView.findViewById(R.id.item_app_icon); - nameView = (TextView) itemView.findViewById(R.id.item_app_name); + iconView = (LauncherIconView) itemView.findViewById(R.id.item_app_icon_launcher); + nameView = (TextView) itemView.findViewById(R.id.item_app_name_launcher); spaceLabelView = (LabelView) itemView.findViewById(R.id.item_app_space_idx); firstOpenDot = itemView.findViewById(R.id.item_first_open_dot); + isHookIcon = (ImageView)itemView.findViewById(R.id.item_app_ishook_launcher); } } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AddAppButton.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AddAppButton.java index a99af813d..9e4c6ef2f 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AddAppButton.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AddAppButton.java @@ -34,7 +34,7 @@ public Drawable getIcon() { @Override public String getName() { - return "Add App"; + return "Add"; } @Override @@ -56,4 +56,9 @@ public boolean canDelete() { public boolean canCreateShortcut() { return false; } + + @Override + public boolean isHook() { + return false; + } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppData.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppData.java index b2759951f..66169dbb5 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppData.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppData.java @@ -23,4 +23,6 @@ public interface AppData { boolean canDelete(); boolean canCreateShortcut(); + + boolean isHook(); } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfo.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfo.java index bde5666c9..8659baaac 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfo.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfo.java @@ -13,4 +13,5 @@ public class AppInfo { public Drawable icon; public CharSequence name; public int cloneCount; + public boolean isHook; } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfoLite.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfoLite.java index b2ad022a6..5b9333b65 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfoLite.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfoLite.java @@ -23,17 +23,20 @@ public AppInfoLite[] newArray(int size) { public String packageName; public String path; public boolean fastOpen; + public boolean isHook; - public AppInfoLite(String packageName, String path, boolean fastOpen) { + public AppInfoLite(String packageName, String path, boolean fastOpen, boolean isHook) { this.packageName = packageName; this.path = path; this.fastOpen = fastOpen; + this.isHook = isHook; } protected AppInfoLite(Parcel in) { this.packageName = in.readString(); this.path = in.readString(); this.fastOpen = in.readByte() != 0; + this.isHook = in.readByte() != 0; } @Override @@ -46,5 +49,6 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.packageName); dest.writeString(this.path); dest.writeByte(this.fastOpen ? (byte) 1 : (byte) 0); + dest.writeByte(this.isHook ? (byte) 1 : (byte) 0); } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/EmptyAppData.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/EmptyAppData.java index 6a3b05311..f8d008c97 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/EmptyAppData.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/EmptyAppData.java @@ -47,4 +47,9 @@ public boolean canDelete() { public boolean canCreateShortcut() { return false; } + + @Override + public boolean isHook() { + return false; + } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/MultiplePackageAppData.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/MultiplePackageAppData.java index 9785be668..ec5d556c9 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/MultiplePackageAppData.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/MultiplePackageAppData.java @@ -17,6 +17,7 @@ public class MultiplePackageAppData implements AppData { public boolean isLoading; public Drawable icon; public String name; + public boolean isHook; public MultiplePackageAppData(PackageAppData target, int userId) { this.userId = userId; @@ -29,6 +30,7 @@ public MultiplePackageAppData(PackageAppData target, int userId) { } } name = target.name; + isHook = target.isHook; } @Override @@ -70,4 +72,9 @@ public boolean canDelete() { public boolean canCreateShortcut() { return true; } + + @Override + public boolean isHook() { + return isHook; + } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/models/PackageAppData.java b/VirtualApp/app/src/main/java/io/virtualapp/home/models/PackageAppData.java index d65acf3c7..1fe5fe188 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/models/PackageAppData.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/models/PackageAppData.java @@ -18,10 +18,12 @@ public class PackageAppData implements AppData { public boolean fastOpen; public boolean isFirstOpen; public boolean isLoading; + public boolean isHook; public PackageAppData(Context context, InstalledAppInfo installedAppInfo) { this.packageName = installedAppInfo.packageName; this.isFirstOpen = !installedAppInfo.isLaunched(0); + this.isHook = installedAppInfo.isHook; loadData(context, installedAppInfo.getApplicationInfo(installedAppInfo.getInstalledUsers()[0])); } @@ -80,4 +82,9 @@ public boolean canDelete() { public boolean canCreateShortcut() { return true; } + + @Override + public boolean isHook() { + return isHook; + } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppRepository.java b/VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppRepository.java index 308a5df87..dfb12487c 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppRepository.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppRepository.java @@ -8,6 +8,7 @@ import com.lody.virtual.GmsSupport; import com.lody.virtual.client.core.InstallStrategy; import com.lody.virtual.client.core.VirtualCore; +import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.remote.InstallResult; import com.lody.virtual.remote.InstalledAppInfo; @@ -60,7 +61,7 @@ public Promise, Throwable, Void> getVirtualApps() { List infos = VirtualCore.get().getInstalledApps(0); List models = new ArrayList<>(); for (InstalledAppInfo info : infos) { - if (!VirtualCore.get().isPackageLaunchable(info.packageName)) { + if (!info.isHook && !VirtualCore.get().isPackageLaunchable(info.packageName)) { continue; } PackageAppData data = new PackageAppData(mContext, info); @@ -101,7 +102,8 @@ private List findAndParseAPKs(Context context, File rootDir, List convertPackageInfoToAppData(Context context, List convertPackageInfoToAppData(Context context, List convertPackageInfoToAppData(Context context, List) adapter); } + */ public void setAdapter(DragSelectRecyclerViewAdapter adapter) { super.setAdapter(adapter); diff --git a/VirtualApp/app/src/main/res/drawable-hdpi/ic_add.png b/VirtualApp/app/src/main/res/drawable-hdpi/ic_add.png deleted file mode 100644 index 481643ecd..000000000 Binary files a/VirtualApp/app/src/main/res/drawable-hdpi/ic_add.png and /dev/null differ diff --git a/VirtualApp/app/src/main/res/drawable-xxhdpi/ic_extension_black_24dp.png b/VirtualApp/app/src/main/res/drawable-xxhdpi/ic_extension_black_24dp.png new file mode 100644 index 000000000..25c6154a1 Binary files /dev/null and b/VirtualApp/app/src/main/res/drawable-xxhdpi/ic_extension_black_24dp.png differ diff --git a/VirtualApp/app/src/main/res/drawable/fab_bg.xml b/VirtualApp/app/src/main/res/drawable/fab_bg.xml deleted file mode 100644 index b96b0d477..000000000 --- a/VirtualApp/app/src/main/res/drawable/fab_bg.xml +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/drawable/home_bg.xml b/VirtualApp/app/src/main/res/drawable/home_bg.xml deleted file mode 100644 index a3df89ef9..000000000 --- a/VirtualApp/app/src/main/res/drawable/home_bg.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/drawable/icon_bg.xml b/VirtualApp/app/src/main/res/drawable/icon_bg.xml deleted file mode 100644 index be368e07f..000000000 --- a/VirtualApp/app/src/main/res/drawable/icon_bg.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/drawable/sel_guide_btn.xml b/VirtualApp/app/src/main/res/drawable/sel_guide_btn.xml deleted file mode 100644 index ec5ae3b50..000000000 --- a/VirtualApp/app/src/main/res/drawable/sel_guide_btn.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/layout/activity_home.xml b/VirtualApp/app/src/main/res/layout/activity_home.xml index 9c31b7d1e..68b6d72e7 100644 --- a/VirtualApp/app/src/main/res/layout/activity_home.xml +++ b/VirtualApp/app/src/main/res/layout/activity_home.xml @@ -22,7 +22,6 @@ fab:layout_heightPercent="12%"> - - - - - - - - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/layout/activity_splash.xml b/VirtualApp/app/src/main/res/layout/activity_splash.xml index f70218443..6a49b8e28 100644 --- a/VirtualApp/app/src/main/res/layout/activity_splash.xml +++ b/VirtualApp/app/src/main/res/layout/activity_splash.xml @@ -18,7 +18,6 @@ android:textSize="26sp" /> diff --git a/VirtualApp/app/src/main/res/layout/activity_users.xml b/VirtualApp/app/src/main/res/layout/activity_users.xml deleted file mode 100644 index d62f55b46..000000000 --- a/VirtualApp/app/src/main/res/layout/activity_users.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/VirtualApp/app/src/main/res/layout/fragment_setup.xml b/VirtualApp/app/src/main/res/layout/fragment_setup.xml deleted file mode 100644 index e8c1c59a9..000000000 --- a/VirtualApp/app/src/main/res/layout/fragment_setup.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - -