如何实现从已安装应用ListView向Blocked App页面ListView迁移条目
Got it, let's walk through building this feature step by step. We'll create a MainActivity showing all installed apps, a BlockedActivity with a list of blocked apps, and wire up the logic to move apps between lists plus add password verification for blocked apps.
1. MainActivity: Load Installed Apps & Handle Item Clicks
First, we'll complete your existing MainActivity code to fetch installed apps, display them in a ListView, and handle clicking items to move them to BlockedActivity.
public class MainActivity extends AppCompatActivity { private PackageManager packageManager = null; private List<ApplicationInfo> installedApps = new ArrayList<>(); private ListView installedAppsListView; private AppListAdapter installedAdapter; private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); packageManager = getPackageManager(); installedAppsListView = findViewById(R.id.list_installed_apps); sharedPreferences = getSharedPreferences("BlockedApps", MODE_PRIVATE); // Fetch installed launchable apps (filter out system apps optionally) loadInstalledApps(); // Set up adapter and click listener installedAdapter = new AppListAdapter(this, installedApps); installedAppsListView.setAdapter(installedAdapter); installedAppsListView.setOnItemClickListener((parent, view, position, id) -> { ApplicationInfo selectedApp = installedApps.get(position); String packageName = selectedApp.packageName; // Remove from current list installedApps.remove(position); installedAdapter.notifyDataSetChanged(); // Add to blocked apps storage Set<String> blockedPackages = sharedPreferences.getStringSet("blocked_packages", new HashSet<>()); blockedPackages.add(packageName); AppBlockAccessibilityService.updateBlockedPackages(this, blockedPackages); // Navigate to BlockedActivity Intent blockedIntent = new Intent(MainActivity.this, BlockedActivity.class); startActivity(blockedIntent); }); } private void loadInstalledApps() { Intent launchIntent = new Intent(Intent.ACTION_MAIN, null); launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(launchIntent, 0); Set<String> blockedPackages = sharedPreferences.getStringSet("blocked_packages", new HashSet<>()); for (ResolveInfo resolveInfo : resolveInfos) { ApplicationInfo appInfo = resolveInfo.activityInfo.applicationInfo; // Skip already blocked apps and system apps (adjust filter as needed) if (!blockedPackages.contains(appInfo.packageName) && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { installedApps.add(appInfo); } } } // Custom adapter for app list items private class AppListAdapter extends ArrayAdapter<ApplicationInfo> { public AppListAdapter(Context context, List<ApplicationInfo> apps) { super(context, 0, apps); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item_app, parent, false); } ApplicationInfo appInfo = getItem(position); TextView appName = convertView.findViewById(R.id.tv_app_name); ImageView appIcon = convertView.findViewById(R.id.iv_app_icon); appName.setText(packageManager.getApplicationLabel(appInfo)); appIcon.setImageDrawable(packageManager.getApplicationIcon(appInfo)); return convertView; } } }
2. BlockedActivity: Manage Blocked Apps List
This activity displays all blocked apps and lets users unblock them (move back to MainActivity's list).
public class BlockedActivity extends AppCompatActivity { private List<ApplicationInfo> blockedApps = new ArrayList<>(); private ListView blockedAppsListView; private BlockedAppAdapter blockedAdapter; private PackageManager packageManager; private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_blocked); setTitle("Blocked App"); packageManager = getPackageManager(); blockedAppsListView = findViewById(R.id.list_blocked_apps); sharedPreferences = getSharedPreferences("BlockedApps", MODE_PRIVATE); // Load blocked apps from storage loadBlockedApps(); blockedAdapter = new BlockedAppAdapter(this, blockedApps); blockedAppsListView.setAdapter(blockedAdapter); // Handle unblocking apps blockedAppsListView.setOnItemClickListener((parent, view, position, id) -> { ApplicationInfo unblockedApp = blockedApps.get(position); String packageName = unblockedApp.packageName; // Remove from blocked list storage Set<String> blockedPackages = sharedPreferences.getStringSet("blocked_packages", new HashSet<>()); blockedPackages.remove(packageName); AppBlockAccessibilityService.updateBlockedPackages(this, blockedPackages); // Update local list and adapter blockedApps.remove(position); blockedAdapter.notifyDataSetChanged(); }); } private void loadBlockedApps() { Set<String> blockedPackages = sharedPreferences.getStringSet("blocked_packages", new HashSet<>()); for (String packageName : blockedPackages) { try { ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0); blockedApps.add(appInfo); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); // Remove invalid package from storage blockedPackages.remove(packageName); AppBlockAccessibilityService.updateBlockedPackages(this, blockedPackages); } } } private class BlockedAppAdapter extends ArrayAdapter<ApplicationInfo> { public BlockedAppAdapter(Context context, List<ApplicationInfo> apps) { super(context, 0, apps); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item_app, parent, false); } ApplicationInfo appInfo = getItem(position); TextView appName = convertView.findViewById(R.id.tv_app_name); ImageView appIcon = convertView.findViewById(R.id.iv_app_icon); appName.setText(packageManager.getApplicationLabel(appInfo)); appIcon.setImageDrawable(packageManager.getApplicationIcon(appInfo)); return convertView; } } }
3. Layout Files
Create these layout files to match the activities:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Installed Apps" android:textSize="18sp" android:padding="16dp" android:background="#f5f5f5"/> <ListView android:id="@+id/list_installed_apps" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
activity_blocked.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Blocked Apps" android:textSize="18sp" android:padding="16dp" android:background="#f5f5f5"/> <ListView android:id="@+id/list_blocked_apps" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
list_item_app.xml (for both lists)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="12dp" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:id="@+id/iv_app_icon" android:layout_width="48dp" android:layout_height="48dp" android:marginEnd="16dp"/> <TextView android:id="@+id/tv_app_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp"/> </LinearLayout>
4. Password Verification for Blocked Apps
To enforce password checks when blocked apps are launched, we'll use an Accessibility Service (the most reliable way to intercept app launches):
AppBlockAccessibilityService.java
public class AppBlockAccessibilityService extends AccessibilityService { private List<String> blockedPackages = new ArrayList<>(); private SharedPreferences sharedPreferences; @Override protected void onServiceConnected() { super.onServiceConnected(); sharedPreferences = getSharedPreferences("BlockedApps", MODE_PRIVATE); refreshBlockedPackages(); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { String packageName = event.getPackageName().toString(); if (blockedPackages.contains(packageName)) { // Launch password verification screen Intent verifyIntent = new Intent(this, PasswordVerificationActivity.class); verifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); verifyIntent.putExtra("TARGET_PACKAGE", packageName); startActivity(verifyIntent); } } } @Override public void onInterrupt() {} public void refreshBlockedPackages() { Set<String> packageSet = sharedPreferences.getStringSet("blocked_packages", new HashSet<>()); blockedPackages.clear(); blockedPackages.addAll(packageSet); } public static void updateBlockedPackages(Context context, Set<String> newPackages) { SharedPreferences.Editor editor = context.getSharedPreferences("BlockedApps", MODE_PRIVATE).edit(); editor.putStringSet("blocked_packages", newPackages); editor.apply(); // Refresh the service if it's running AccessibilityManager manager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); List<AccessibilityServiceInfo> services = manager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC); for (AccessibilityServiceInfo info : services) { if (info.getId().contains(AppBlockAccessibilityService.class.getName())) { ((AppBlockAccessibilityService) manager.getAccessibilityService(info.getId())).refreshBlockedPackages(); break; } } } }
PasswordVerificationActivity.java
public class PasswordVerificationActivity extends AppCompatActivity { private String targetPackage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_password_verification); targetPackage = getIntent().getStringExtra("TARGET_PACKAGE"); EditText passwordInput = findViewById(R.id.et_password); Button verifyBtn = findViewById(R.id.btn_verify); verifyBtn.setOnClickListener(v -> { String input = passwordInput.getText().toString().trim(); // Replace with your actual password validation logic if ("your_secure_password".equals(input)) { Toast.makeText(this, "Verification successful", Toast.LENGTH_SHORT).show(); finish(); } else { Toast.makeText(this, "Incorrect password", Toast.LENGTH_SHORT).show(); // Close the blocked app try { Intent closeIntent = getPackageManager().getLaunchIntentForPackage(targetPackage); if (closeIntent != null) { closeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(closeIntent); } finish(); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); finish(); } } }); } }
Register Accessibility Service in Manifest
Add this to your AndroidManifest.xml:
<service android:name=".AppBlockAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService"/> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config"/> </service>
accessibility_service_config.xml (res/xml/)
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_desc"/>
Key Notes
- Data Persistence: We use SharedPreferences to store blocked app package names, so the list survives app restarts.
- Accessibility Permission: Users need to enable the accessibility service in system settings. Add a guide in your app to direct users there.
- Performance: For large app lists, use background threads (Coroutines or AsyncTask) to fetch installed apps to avoid UI freezes.
内容的提问来源于stack exchange,提问作者ayoub

