diff --git a/VirtualApp/app/src/main/java/io/virtualapp/abs/Function.java b/VirtualApp/app/src/main/java/io/virtualapp/abs/Function.java new file mode 100644 index 000000000..cc761bb6f --- /dev/null +++ b/VirtualApp/app/src/main/java/io/virtualapp/abs/Function.java @@ -0,0 +1,8 @@ +package io.virtualapp.abs; + +/** + * author: weishu on 18/2/3. + */ +public interface Function { + R apply(T r); +} 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 248973cc8..230e3c818 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/HomeActivity.java @@ -43,6 +43,7 @@ import io.virtualapp.VApp; import io.virtualapp.VCommends; import io.virtualapp.about.AboutActivity; +import io.virtualapp.abs.Function; import io.virtualapp.abs.nestedadapter.SmartRecyclerAdapter; import io.virtualapp.abs.ui.VActivity; import io.virtualapp.abs.ui.VUiKit; @@ -77,7 +78,13 @@ public class HomeActivity extends VActivity implements HomeContract.HomeView { private View mMenuView; private PopupMenu mPopupMenu; private View mBottomArea; + private View mLeftArea; + private View mRightArea; private View mCreateShortcutBox; + private View mClearAppBox; + private TextView mClearAppTextView; + private View mKillAppBox; + private TextView mKillAppTextView; private TextView mCreateShortcutTextView; private View mDeleteAppBox; private TextView mDeleteAppTextView; @@ -212,6 +219,12 @@ private void bindViews() { mLauncherView = (RecyclerView) findViewById(R.id.home_launcher); mMenuView = findViewById(R.id.home_menu); mBottomArea = findViewById(R.id.bottom_area); + mLeftArea = findViewById(R.id.left_area); + mRightArea = findViewById(R.id.right_area); + mClearAppBox = findViewById(R.id.clear_app_area); + mClearAppTextView = (TextView) findViewById(R.id.clear_app_text); + mKillAppBox = findViewById(R.id.kill_app_area); + mKillAppTextView = (TextView) findViewById(R.id.kill_app_text); mCreateShortcutBox = findViewById(R.id.create_shortcut_area); mCreateShortcutTextView = (TextView) findViewById(R.id.create_shortcut_text); mDeleteAppBox = findViewById(R.id.delete_app_area); @@ -253,8 +266,8 @@ private void deleteApp(int position) { } AppData data = mLaunchpadAdapterList.get(position); AlertDialog alertDialog = new AlertDialog.Builder(this) - .setTitle("Delete app") - .setMessage("Do you want to delete " + data.getName() + "?") + .setTitle(R.string.home_menu_delete_title) + .setMessage(getResources().getString(R.string.home_menu_delete_content, data.getName())) .setPositiveButton(android.R.string.yes, (dialog, which) -> { mPresenter.deleteApp(data); }) @@ -267,6 +280,48 @@ private void deleteApp(int position) { } } + private void clearApp(int position) { + List mLaunchpadAdapterList = mLaunchpadAdapter.getList(); + if (position >= mLaunchpadAdapterList.size() || position < 0) { + return; + } + AppData data = mLaunchpadAdapterList.get(position); + AlertDialog alertDialog = new AlertDialog.Builder(this) + .setTitle(R.string.home_menu_clear_title) + .setMessage(getResources().getString(R.string.home_menu_clear_content, data.getName())) + .setPositiveButton(android.R.string.yes, (dialog, which) -> { + mPresenter.clearApp(data); + }) + .setNegativeButton(android.R.string.no, null) + .create(); + try { + alertDialog.show(); + } catch (Throwable ignored) { + // BadTokenException. + } + } + + private void killApp(int position) { + List mLaunchpadAdapterList = mLaunchpadAdapter.getList(); + if (position >= mLaunchpadAdapterList.size() || position < 0) { + return; + } + AppData data = mLaunchpadAdapterList.get(position); + AlertDialog alertDialog = new AlertDialog.Builder(this) + .setTitle(R.string.home_menu_kill_title) + .setMessage(getResources().getString(R.string.home_menu_kill_content, data.getName())) + .setPositiveButton(android.R.string.yes, (dialog, which) -> { + mPresenter.killApp(data); + }) + .setNegativeButton(android.R.string.no, null) + .create(); + try { + alertDialog.show(); + } catch (Throwable ignored) { + // BadTokenException. + } + } + private void createShortcut(int position) { if (position < 0) { return; @@ -287,35 +342,62 @@ public void showBottomAction() { mBottomArea.setTranslationY(mBottomArea.getHeight()); mBottomArea.setVisibility(View.VISIBLE); mBottomArea.animate().translationY(0).setDuration(500L).start(); + mLeftArea.setTranslationX(-mLeftArea.getWidth()); + mLeftArea.setVisibility(View.VISIBLE); + mLeftArea.animate().translationX(0).setDuration(500L).start(); + mRightArea.setTranslationX(mRightArea.getWidth()); + mRightArea.setVisibility(View.VISIBLE); + mRightArea.animate().translationX(0).setDuration(500L).start(); } @Override public void hideBottomAction() { mBottomArea.setTranslationY(0); - ObjectAnimator transAnim = ObjectAnimator.ofFloat(mBottomArea, "translationY", 0, mBottomArea.getHeight()); - transAnim.addListener(new Animator.AnimatorListener() { + + class HideAnimatorListener implements Animator.AnimatorListener { + + View v; + HideAnimatorListener(View v) { + this.v = v; + } + @Override - public void onAnimationStart(Animator animator) { + public void onAnimationStart(Animator animation) { } @Override - public void onAnimationEnd(Animator animator) { - mBottomArea.setVisibility(View.GONE); + public void onAnimationEnd(Animator animation) { + v.setVisibility(View.GONE); } @Override - public void onAnimationCancel(Animator animator) { - mBottomArea.setVisibility(View.GONE); + public void onAnimationCancel(Animator animation) { + v.setVisibility(View.GONE); } @Override - public void onAnimationRepeat(Animator animator) { + public void onAnimationRepeat(Animator animation) { } - }); + } + + ObjectAnimator transAnim = ObjectAnimator.ofFloat(mBottomArea, "translationY", 0, mBottomArea.getHeight()); + transAnim.addListener(new HideAnimatorListener(mBottomArea)); transAnim.setDuration(500L); transAnim.start(); + + mLeftArea.setTranslationX(0); + ObjectAnimator transAnimLeft = ObjectAnimator.ofFloat(mLeftArea, "translationX", 0, -mLeftArea.getWidth()); + transAnim.addListener(new HideAnimatorListener(mLeftArea)); + transAnimLeft.setDuration(500L); + transAnimLeft.start(); + + mRightArea.setTranslationX(0); + ObjectAnimator transAnimRight = ObjectAnimator.ofFloat(mRightArea, "translationX", 0, mRightArea.getWidth()); + transAnim.addListener(new HideAnimatorListener(mRightArea)); + transAnimRight.setDuration(500L); + transAnimRight.start(); } @Override @@ -423,6 +505,8 @@ private class LauncherTouchCallback extends ItemTouchHelper.SimpleCallback { int[] location = new int[2]; boolean upAtDeleteAppArea; boolean upAtCreateShortcutArea; + boolean upAtClearAppArea; + boolean upAtKillAppArea; RecyclerView.ViewHolder dragHolder; LauncherTouchCallback() { @@ -484,7 +568,7 @@ public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionStat @Override public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) { - if (upAtCreateShortcutArea || upAtDeleteAppArea) { + if (upAtCreateShortcutArea || upAtDeleteAppArea || upAtClearAppArea || upAtKillAppArea) { return false; } try { @@ -514,6 +598,10 @@ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHol createShortcut(viewHolder.getAdapterPosition()); } else if (upAtDeleteAppArea) { deleteApp(viewHolder.getAdapterPosition()); + } else if (upAtClearAppArea) { + clearApp(viewHolder.getAdapterPosition()); + } else if (upAtKillAppArea) { + killApp(viewHolder.getAdapterPosition()); } } dragHolder = null; @@ -537,27 +625,46 @@ public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHo int y = (int) (location[1] + dY); mBottomArea.getLocationInWindow(location); - int baseLine = location[1] - mBottomArea.getHeight(); + // int baseLine = location[1] - mBottomArea.getHeight(); + int baseLine = location[1]; // shorten area if (y >= baseLine) { mDeleteAppBox.getLocationInWindow(location); int deleteAppAreaStartX = location[0]; if (x < deleteAppAreaStartX) { - upAtCreateShortcutArea = true; - upAtDeleteAppArea = false; - mCreateShortcutTextView.setTextColor(Color.parseColor("#0099cc")); - mDeleteAppTextView.setTextColor(Color.WHITE); + setMenuView(true, false, false, false); + return; } else { - upAtDeleteAppArea = true; - upAtCreateShortcutArea = false; - mDeleteAppTextView.setTextColor(Color.parseColor("#0099cc")); - mCreateShortcutTextView.setTextColor(Color.WHITE); + setMenuView( false, true, false, false); + return; } - } else { - upAtCreateShortcutArea = false; - upAtDeleteAppArea = false; - mDeleteAppTextView.setTextColor(Color.WHITE); - mCreateShortcutTextView.setTextColor(Color.WHITE); } + + mLeftArea.getLocationInWindow(location); + if (x <= location[0]) { + setMenuView(false, false, true, false); + return; + } + + mRightArea.getLocationInWindow(location); + if (x >= location[0]) { + setMenuView(false, false, false, true); + return; + } + + setMenuView( false, false, false, false); + } + + private void setMenuView(boolean showCreateShortcut, boolean showDelete, boolean showClear, boolean showStop) { + upAtDeleteAppArea = showDelete; + upAtCreateShortcutArea = showCreateShortcut; + upAtKillAppArea = showStop; + upAtClearAppArea = showClear; + int color = Color.parseColor("#0099cc"); + Function getColor = r -> r ? color : Color.WHITE; + mKillAppTextView.setTextColor(getColor.apply(showStop)); + mCreateShortcutTextView.setTextColor(getColor.apply(showCreateShortcut)); + mDeleteAppTextView.setTextColor(getColor.apply(showDelete)); + mClearAppTextView.setTextColor(getColor.apply(showClear)); } } diff --git a/VirtualApp/app/src/main/java/io/virtualapp/home/HomeContract.java b/VirtualApp/app/src/main/java/io/virtualapp/home/HomeContract.java index 90eec3605..bcd7b197a 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/HomeContract.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/HomeContract.java @@ -49,6 +49,10 @@ void deleteApp(AppData data); void createShortcut(AppData data); - } + + void clearApp(AppData data); + + void killApp(AppData data); + } } 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 8c5bde34a..c470869ab 100644 --- a/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java +++ b/VirtualApp/app/src/main/java/io/virtualapp/home/HomePresenterImpl.java @@ -251,4 +251,24 @@ public String getName(String originName) { } } + @Override + public void clearApp(AppData data) { + if (data instanceof PackageAppData) { + VirtualCore.get().clearPackage(((PackageAppData) data).packageName); + } else { + MultiplePackageAppData appData = (MultiplePackageAppData) data; + VirtualCore.get().clearPackageAsUser(appData.userId, appData.appInfo.packageName); + } + } + + @Override + public void killApp(AppData data) { + if (data instanceof PackageAppData) { + VirtualCore.get().killApp(((PackageAppData) data).packageName, 0); + } else { + MultiplePackageAppData appData = (MultiplePackageAppData) data; + VirtualCore.get().killApp(((MultiplePackageAppData) data).appInfo.packageName, appData.userId); + } + } + } diff --git a/VirtualApp/app/src/main/res/layout/activity_home.xml b/VirtualApp/app/src/main/res/layout/activity_home.xml index 9c31b7d1e..77deb7ec5 100644 --- a/VirtualApp/app/src/main/res/layout/activity_home.xml +++ b/VirtualApp/app/src/main/res/layout/activity_home.xml @@ -58,13 +58,86 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + + 为了让VAExposed内部运行的应用不会频繁被系统杀死,请允许把VAExposed加入电池优化白名单;同时,VAExposed会尽量保证APP不滥用此权限。请在接下来的系统弹窗中选择"允许" :) 朕同意了 常见问题 + 清除\n数据 + 强制\n停止 + 删除应用 + 是否要从 VAExposed 删除 %1$s ? + 清除数据 + 确定要删除 %1$s 的数据吗? + 强制停止 + 是否要强制停止 %1$s 的运行? diff --git a/VirtualApp/app/src/main/res/values/strings.xml b/VirtualApp/app/src/main/res/values/strings.xml index 196848170..7e772e898 100644 --- a/VirtualApp/app/src/main/res/values/strings.xml +++ b/VirtualApp/app/src/main/res/values/strings.xml @@ -63,5 +63,13 @@ Please allow VAExposed running in background, otherwise you may not receive notification of some inner app. Allow FAQ + Clear\nData + Force\nStop + Delete App + Do you want to delete %1$s ? + Clear App Data + Do you want to clear data of %1$s ? + Force Stop + Do you want to force stop %1$s, this may cause it works Unexpectedly.