-
-
Notifications
You must be signed in to change notification settings - Fork 589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android 15 Private Space Integration #2345
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,8 @@ | |
import android.content.Context; | ||
import android.content.Intent; | ||
import android.content.IntentFilter; | ||
import android.content.pm.LauncherApps; | ||
import android.content.pm.LauncherUserInfo; | ||
import android.content.SharedPreferences; | ||
import android.content.pm.PackageManager; | ||
import android.content.pm.ResolveInfo; | ||
|
@@ -19,6 +21,8 @@ | |
import android.graphics.Rect; | ||
import android.os.Build; | ||
import android.os.Bundle; | ||
import android.os.UserHandle; | ||
import android.os.UserManager; | ||
import android.preference.PreferenceManager; | ||
import android.provider.Settings; | ||
import android.text.Editable; | ||
|
@@ -44,8 +48,11 @@ | |
import android.widget.TextView.OnEditorActionListener; | ||
|
||
import androidx.annotation.NonNull; | ||
import androidx.annotation.RequiresApi; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import fr.neamar.kiss.adapter.RecordAdapter; | ||
import fr.neamar.kiss.broadcast.IncomingCallHandler; | ||
|
@@ -213,6 +220,11 @@ public void onReceive(Context context, Intent intent) { | |
|
||
// Run GC once to free all the garbage accumulated during provider initialization | ||
System.gc(); | ||
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { | ||
if (intent.getAction().equalsIgnoreCase(Intent.ACTION_PROFILE_AVAILABLE) | ||
|| intent.getAction().equalsIgnoreCase(Intent.ACTION_PROFILE_UNAVAILABLE)) { | ||
privateSpaceStateEvent(intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class)); | ||
} | ||
Comment on lines
+223
to
+227
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Private space is just another profile like e.g. any work profile. So if I read this correctly, these change here is not needed. |
||
} | ||
|
||
// New provider might mean new favorites | ||
|
@@ -228,6 +240,12 @@ public void onReceive(Context context, Intent intent) { | |
this.registerReceiver(mReceiver, intentFilterLoad, Context.RECEIVER_EXPORTED); | ||
this.registerReceiver(mReceiver, intentFilterLoadOver, Context.RECEIVER_EXPORTED); | ||
this.registerReceiver(mReceiver, intentFilterFullLoadOver, Context.RECEIVER_EXPORTED); | ||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { | ||
IntentFilter intentFilterProfileAvailable = new IntentFilter(Intent.ACTION_PROFILE_AVAILABLE); | ||
IntentFilter intentFilterProfileUnAvailable = new IntentFilter(Intent.ACTION_PROFILE_UNAVAILABLE); | ||
this.registerReceiver(mReceiver, intentFilterProfileAvailable, Context.RECEIVER_EXPORTED); | ||
this.registerReceiver(mReceiver, intentFilterProfileUnAvailable, Context.RECEIVER_EXPORTED); | ||
} | ||
Comment on lines
+243
to
+248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, see |
||
} | ||
else { | ||
this.registerReceiver(mReceiver, intentFilterLoad); | ||
|
@@ -402,6 +420,19 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMen | |
super.onCreateContextMenu(menu, v, menuInfo); | ||
MenuInflater inflater = getMenuInflater(); | ||
inflater.inflate(R.menu.menu_main, menu); | ||
|
||
MenuItem privateSpaceItem = menu.findItem(R.id.private_space); | ||
if (privateSpaceItem != null) { | ||
if ((android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) | ||
|| (getPrivateUser() == null)) { | ||
privateSpaceItem.setVisible(false); | ||
} else if (isPrivateSpaceUnlocked()) { | ||
privateSpaceItem.setTitle("Lock Private Space"); | ||
} else { | ||
privateSpaceItem.setTitle("Unlock Private Space"); | ||
Comment on lines
+429
to
+432
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't forget about resources for titles here. |
||
} | ||
} | ||
|
||
forwarderManager.onCreateContextMenu(menu); | ||
} | ||
|
||
|
@@ -557,6 +588,9 @@ public boolean onOptionsItemSelected(MenuItem item) { | |
} else if (itemId == R.id.preferences) { | ||
startActivity(new Intent(this, SettingsActivity.class)); | ||
return true; | ||
} else if (itemId == R.id.private_space) { | ||
switchPrivateSpaceState(); | ||
return true; | ||
} | ||
return super.onOptionsItemSelected(item); | ||
} | ||
|
@@ -566,7 +600,6 @@ public boolean onCreateOptionsMenu(Menu menu) { | |
super.onCreateOptionsMenu(menu); | ||
MenuInflater inflater = getMenuInflater(); | ||
inflater.inflate(R.menu.menu_main, menu); | ||
|
||
return true; | ||
} | ||
|
||
|
@@ -689,6 +722,64 @@ public void onAnimationEnd(Animator animation) { | |
} | ||
} | ||
|
||
@RequiresApi(35) | ||
private UserHandle getPrivateUser() { | ||
final UserManager manager = (UserManager) this.getSystemService(Context.USER_SERVICE); | ||
assert manager != null; | ||
|
||
final LauncherApps launcher = (LauncherApps) this.getSystemService(Context.LAUNCHER_APPS_SERVICE); | ||
assert launcher != null; | ||
|
||
List<UserHandle> users = launcher.getProfiles(); | ||
|
||
UserHandle privateUser = null; | ||
for (UserHandle user : users) { | ||
if (Objects.requireNonNull(launcher.getLauncherUserInfo(user)).getUserType().equalsIgnoreCase(UserManager.USER_TYPE_PROFILE_PRIVATE)) { | ||
privateUser = user; | ||
break; | ||
} | ||
} | ||
return privateUser; | ||
} | ||
|
||
private boolean isPrivateSpaceUnlocked() { | ||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { | ||
return false; | ||
} | ||
|
||
final UserManager manager = (UserManager) this.getSystemService(Context.USER_SERVICE); | ||
assert manager != null; | ||
|
||
UserHandle user = getPrivateUser(); | ||
return !manager.isQuietModeEnabled(user); | ||
} | ||
|
||
@RequiresApi(35) | ||
private void switchPrivateSpaceState() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could annotate the method |
||
final UserManager manager = (UserManager) this.getSystemService(Context.USER_SERVICE); | ||
assert manager != null; | ||
|
||
UserHandle user = getPrivateUser(); | ||
manager.requestQuietModeEnabled(!manager.isQuietModeEnabled(user), user); | ||
} | ||
|
||
@RequiresApi(35) | ||
private void privateSpaceStateEvent(UserHandle handle) { | ||
if (handle == null) { | ||
return; | ||
} | ||
|
||
final LauncherApps launcher = (LauncherApps) this.getSystemService(Context.LAUNCHER_APPS_SERVICE); | ||
|
||
LauncherUserInfo info = launcher.getLauncherUserInfo(handle); | ||
if (info != null) { | ||
if (info.getUserType().equalsIgnoreCase(UserManager.USER_TYPE_PROFILE_PRIVATE)) { | ||
Log.d(TAG, "Private Space state changed"); | ||
// TODO: Check if private space state changed and change app view accordingly | ||
} | ||
} | ||
} | ||
|
||
Comment on lines
+766
to
+782
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, see |
||
public void onFavoriteChange() { | ||
forwarderManager.onFavoriteChange(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import android.content.pm.ApplicationInfo; | ||
import android.content.pm.LauncherActivityInfo; | ||
import android.content.pm.LauncherApps; | ||
import android.content.pm.LauncherUserInfo; | ||
import android.content.pm.PackageManager; | ||
import android.content.pm.ResolveInfo; | ||
import android.os.Build; | ||
|
@@ -55,6 +56,10 @@ protected List<AppPojo> doInBackground(Void... params) { | |
|
||
// Handle multi-profile support introduced in Android 5 (#542) | ||
for (android.os.UserHandle profile : manager.getUserProfiles()) { | ||
LauncherUserInfo info = null; | ||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { | ||
info = launcherApps.getLauncherUserInfo(profile); | ||
} | ||
UserHandle user = new UserHandle(manager.getSerialNumberForUser(profile), profile); | ||
for (LauncherActivityInfo activityInfo : launcherApps.getActivityList(null, profile)) { | ||
if (isCancelled()) { | ||
|
@@ -63,7 +68,18 @@ protected List<AppPojo> doInBackground(Void... params) { | |
ApplicationInfo appInfo = activityInfo.getApplicationInfo(); | ||
boolean disabled = PackageManagerUtils.isAppSuspended(appInfo) || isQuietModeEnabled(manager, profile); | ||
final AppPojo app = createPojo(user, appInfo.packageName, activityInfo.getName(), activityInfo.getLabel(), disabled, excludedAppList, excludedFromHistoryAppList, excludedShortcutsAppList); | ||
apps.add(app); | ||
if ((android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you try to move code related to private space to separate class? Code in |
||
&& (info != null)) { | ||
if (!info.getUserType().equalsIgnoreCase(UserManager.USER_TYPE_PROFILE_PRIVATE)) { | ||
apps.add(app); | ||
} else { | ||
if (!isQuietModeEnabled(manager, profile)) { | ||
apps.add(app); | ||
} | ||
} | ||
} else { | ||
apps.add(app); | ||
} | ||
} | ||
} | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,15 @@ | |
package fr.neamar.kiss.loader; | ||
|
||
import android.content.Context; | ||
import android.content.SharedPreferences; | ||
import android.content.pm.LauncherApps; | ||
import android.content.pm.LauncherUserInfo; | ||
import android.content.pm.ShortcutInfo; | ||
import android.os.Build; | ||
import android.os.UserManager; | ||
import android.preference.PreferenceManager; | ||
|
||
import androidx.annotation.RequiresApi; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
@@ -33,6 +39,8 @@ protected List<ShortcutPojo> doInBackground(Void... params) { | |
return new ArrayList<>(); | ||
} | ||
|
||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | ||
|
||
List<ShortcutRecord> records = DBHelper.getShortcuts(context); | ||
DataHandler dataHandler = KissApplication.getApplication(context).getDataHandler(); | ||
TagsHandler tagsHandler = dataHandler.getTagsHandler(); | ||
|
@@ -52,8 +60,13 @@ protected List<ShortcutPojo> doInBackground(Void... params) { | |
// get all oreo shortcuts from system directly | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); | ||
LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); | ||
List<ShortcutInfo> shortcutInfos = ShortcutUtil.getAllShortcuts(context); | ||
for (ShortcutInfo shortcutInfo : shortcutInfos) { | ||
LauncherUserInfo info = null; | ||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { | ||
info = launcherApps.getLauncherUserInfo(shortcutInfo.getUserHandle()); | ||
} | ||
if (isCancelled()) { | ||
break; | ||
} | ||
|
@@ -62,7 +75,16 @@ protected List<ShortcutPojo> doInBackground(Void... params) { | |
if (shortcutRecord != null) { | ||
boolean disabled = PackageManagerUtils.isAppSuspended(context, shortcutInfo.getPackage(), new UserHandle(context, shortcutInfo.getUserHandle())) || userManager.isQuietModeEnabled(shortcutInfo.getUserHandle()); | ||
ShortcutPojo pojo = createPojo(shortcutRecord, tagsHandler, ShortcutUtil.getComponentName(context, shortcutInfo), shortcutInfo.isPinned(), shortcutInfo.isDynamic(), disabled); | ||
pojos.add(pojo); | ||
if ((android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) | ||
&& (info != null)) { | ||
boolean privateSpaceShortcutsDisabled = prefs.getBoolean("disable-private-space-shortcuts", true); | ||
if (shouldAddShortcut(userManager, info, shortcutInfo.getUserHandle(), | ||
privateSpaceShortcutsDisabled)) { | ||
pojos.add(pojo); | ||
} | ||
} else { | ||
pojos.add(pojo); | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -71,10 +93,30 @@ protected List<ShortcutPojo> doInBackground(Void... params) { | |
return pojos; | ||
} | ||
|
||
@RequiresApi(35) | ||
private boolean shouldAddShortcut(UserManager manager, LauncherUserInfo info, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Method to check if shortcuts should be hidden is already there, it's |
||
android.os.UserHandle profile, boolean privateSpaceShortcutsDisabled) { | ||
if (!info.getUserType().equalsIgnoreCase(UserManager.USER_TYPE_PROFILE_PRIVATE)) { | ||
return true; | ||
} else { | ||
if (privateSpaceShortcutsDisabled) { | ||
return false; | ||
} | ||
else return !isQuietModeEnabled(manager, profile); | ||
} | ||
} | ||
|
||
private ShortcutPojo createPojo(ShortcutRecord shortcutRecord, TagsHandler tagsHandler, String componentName, boolean pinned, boolean dynamic, boolean disabled) { | ||
ShortcutPojo pojo = new ShortcutPojo(shortcutRecord, componentName, pinned, dynamic, disabled); | ||
pojo.setName(shortcutRecord.name); | ||
pojo.setTags(tagsHandler.getTags(pojo.id)); | ||
return pojo; | ||
} | ||
|
||
private boolean isQuietModeEnabled(UserManager manager, android.os.UserHandle profile) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||
return manager.isQuietModeEnabled(profile); | ||
} | ||
return false; | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how are these theme changes related to private space? Is this fix for differet problem? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<resources> | ||
|
||
<!-- TODO: Remove once activities handle insets. --> | ||
<style name="BaseThemeLight" parent="@android:style/Theme.Holo.Light.NoActionBar"> | ||
<item name="appSelectableItemBackground">?android:attr/selectableItemBackground</item> | ||
<item name="android:actionMenuTextColor">@android:color/white</item> | ||
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> | ||
</style> | ||
|
||
<style name="BaseThemeDark" parent="@android:style/Theme.Holo.NoActionBar"> | ||
<item name="appSelectableItemBackground">?android:attr/selectableItemBackground</item> | ||
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> | ||
</style> | ||
</resources> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this category needed for? KISS should be launcher only