[SOLVED] Add widgets to secure lock screen - Galaxy S 4 Developer Discussion [Developers-Only]
Hey guys. I am working with @MohammadAG to bring back the widgets on secure lock screen. He successfully done this on android 4.1 and 4.2 and 4.3. However, he does not have the ability to test for android 4.4. So I downloaded his repo from github and am trying to make it work again.
However, i have no idea where the control is being made. I have the Google source code downloaded as well. I can't find anything that controls the adding of the widgets based off the security. I've grepped over the whole thing using keywords like "addWidgets" and "secure" etc. I can't figure out where the call is being made to show the widgets.
Any help would be greatly appreciated! Thanks everyone!
frameworks/base/packages/Keyguard/src/com/android/keyguard
Code:
[email protected] /media/broodplank/linuxdata/AOSP-KK/frameworks/base/packages/Keyguard/src/com/android/keyguard $ ls | grep Widget
CameraWidgetFrame.java
KeyguardWidgetCarousel.java
KeyguardWidgetFrame.java
KeyguardWidgetPager.java
I think you're searching or this? Or am I wrong?
oh btw, I am wrong, I think I know what you mean.
Do you mean this?
https://github.com/CyanogenMod/andr.../base/packages/Keyguard/res/values/config.xml
or
https://github.com/CyanogenMod/andr...ages/SettingsProvider/res/values/defaults.xml
<string name="def_lockscreen_targets">#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.mms/.ui.ConversationList;S.icon_resource=ic_lockscreen_sms_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.andrew.apollo/.ui.activities.HomeActivity;S.icon_resource=ic_lockscreen_music_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.dialer/.DialtactsActivity;S.icon_resource=ic_lockscreen_phone_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.browser/.BrowserActivity;S.icon_resource=ic_lockscreen_browser_normal;end</string>
So thats the place where it gets added
broodplank1337 said:
frameworks/base/packages/Keyguard/src/com/android/keyguard
Code:
[email protected] /media/broodplank/linuxdata/AOSP-KK/frameworks/base/packages/Keyguard/src/com/android/keyguard $ ls | grep Widget
CameraWidgetFrame.java
KeyguardWidgetCarousel.java
KeyguardWidgetFrame.java
KeyguardWidgetPager.java
I think you're searching or this? Or am I wrong?
oh btw, I am wrong, I think I know what you mean.
Do you mean this?
https://github.com/CyanogenMod/andr.../base/packages/Keyguard/res/values/config.xml
or
https://github.com/CyanogenMod/andr...ages/SettingsProvider/res/values/defaults.xml
<string name="def_lockscreen_targets">#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.mms/.ui.ConversationList;S.icon_resource=ic_lockscreen_sms_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.andrew.apollo/.ui.activities.HomeActivity;S.icon_resource=ic_lockscreen_music_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.dialer/.DialtactsActivity;S.icon_resource=ic_lockscreen_phone_normal;end|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.android.browser/.BrowserActivity;S.icon_resource=ic_lockscreen_browser_normal;end</string>
So thats the place where it gets added
Click to expand...
Click to collapse
Actually, you were more on track in the first segment of your post
I need to figure out where the call is being made to disable the widgets on the secure lockscreen. If i use what MohammadAG already has, and just change the classes to match the new ones, i can get the "add widget" plus sign, but none of my other already added widgets are present. Nor, when i add a widget, it does not get shown on the secure lockscreen, however, when i set the lockscreen to "swipe" i can see the newly added widget that was added..
I think his method of allowing the widgets works, and enabling the add widget option, but it doesn't save them or let the already added widgets show. Which is where i am having the difficulty. I can't figure out what is preventing the saved ones from being added.
Thanks for your reply!! All replies help and juggle my mind through everything.
elesbb said:
Actually, you were more on track in the first segment of your post
I need to figure out where the call is being made to disable the widgets on the secure lockscreen. If i use what MohammadAG already has, and just change the classes to match the new ones, i can get the "add widget" plus sign, but none of my other already added widgets are present. Nor, when i add a widget, it does not get shown on the secure lockscreen, however, when i set the lockscreen to "swipe" i can see the newly added widget that was added..
I think his method of allowing the widgets works, and enabling the add widget option, but it doesn't save them or let the already added widgets show. Which is where i am having the difficulty. I can't figure out what is preventing the saved ones from being added.
Thanks for your reply!! All replies help and juggle my mind through everything.
Click to expand...
Click to collapse
Ok lol
I think I found it this time
in Settings (SecuritySettings.java)
Code:
// Enable or disable keyguard widget checkbox based on DPM state
mEnableKeyguardWidgets = (CheckBoxPreference) root.findPreference(KEY_ENABLE_WIDGETS);
if (mEnableKeyguardWidgets != null) {
if (ActivityManager.isLowRamDeviceStatic()
|| mLockPatternUtils.isLockScreenDisabled()) {
// Widgets take a lot of RAM, so disable them on low-memory devices
PreferenceGroup securityCategory
= (PreferenceGroup) root.findPreference(KEY_SECURITY_CATEGORY);
if (securityCategory != null) {
securityCategory.removePreference(root.findPreference(KEY_ENABLE_WIDGETS));
mEnableKeyguardWidgets = null;
}
} else {
final boolean disabled = (0 != (mDPM.getKeyguardDisabledFeatures(null)
& [B]DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL[/B]));
if (disabled) {
mEnableKeyguardWidgets.setSummary(
R.string.security_enable_widgets_disabled_summary);
} else {
mEnableKeyguardWidgets.setSummary("");
}
mEnableKeyguardWidgets.setEnabled(!disabled);
}
}
so the rest of the implementation should be in frameworks/base/policy or anything like that
broodplank1337 said:
Ok lol
I think I found it this time
in Settings (SecuritySettings.java)
Code:
// Enable or disable keyguard widget checkbox based on DPM state
mEnableKeyguardWidgets = (CheckBoxPreference) root.findPreference(KEY_ENABLE_WIDGETS);
if (mEnableKeyguardWidgets != null) {
if (ActivityManager.isLowRamDeviceStatic()
|| mLockPatternUtils.isLockScreenDisabled()) {
// Widgets take a lot of RAM, so disable them on low-memory devices
PreferenceGroup securityCategory
= (PreferenceGroup) root.findPreference(KEY_SECURITY_CATEGORY);
if (securityCategory != null) {
securityCategory.removePreference(root.findPreference(KEY_ENABLE_WIDGETS));
mEnableKeyguardWidgets = null;
}
} else {
final boolean disabled = (0 != (mDPM.getKeyguardDisabledFeatures(null)
& [B]DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL[/B]));
if (disabled) {
mEnableKeyguardWidgets.setSummary(
R.string.security_enable_widgets_disabled_summary);
} else {
mEnableKeyguardWidgets.setSummary("");
}
mEnableKeyguardWidgets.setEnabled(!disabled);
}
}
so the rest of the implementation should be in frameworks/base/policy or anything like that
Click to expand...
Click to collapse
Yes that is the part for the settings activity to allow one to enable widgets. I got that one working
I actually found a method called "isSecure" that is controlling a lot. I am getting closer!
I have it working perfectly
However camera isnt working yet. I think i know where to look for that though. Thanks broodPlank!! I love having someone to converse about this stuff with! My brothers are useless they are like.. smali.. what? methods what? lol thank you!
elesbb said:
Yes that is the part for the settings activity to allow one to enable widgets. I got that one working
I actually found a method called "isSecure" that is controlling a lot. I am getting closer!
I have it working perfectly
However camera isnt working yet. I think i know where to look for that though. Thanks broodPlank!! I love having someone to converse about this stuff with! My brothers are useless they are like.. smali.. what? methods what? lol thank you!
Click to expand...
Click to collapse
Oh ok nice, I actually thought you had that working already since it was pretty easy to find
Nice that you found it! the isSecure string returned this for me:
Code:
[email protected] /media/broodplank/linuxdata/AOSP-KK/frameworks/base/packages $ grep -r 'isSecure' ../Keyguard/src/com/android/keyguard/KeyguardService.java: public boolean isSecure() {
./Keyguard/src/com/android/keyguard/KeyguardService.java: return mKeyguardViewMediator.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: mShowing = (mUpdateMonitor.isDeviceProvisioned() || mLockPatternUtils.isSecure())
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (mScreenOn && mLockPatternUtils.isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: public boolean isSecure() {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: return mLockPatternUtils.isSecure()
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: return mKeyguardDonePending || !isSecure();
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (lockPatternUtils.isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: boolean isSecure = lockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (!isSecure || showsWhileLocked) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (!isSecure) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
./Keyguard/src/com/android/keyguard/EmergencyButton.java: enabled = mLockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardSelectorView.java: boolean secureCameraDisabled = mLockPatternUtils.isSecure()
./Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java: public boolean isSecure() {
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: public boolean isSecure() {
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: return service.isSecure();
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: Slog.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: Slog.w(TAG, "isSecure(): NO SERVICE!");
./SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java: && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
Great!
Also good that you know where to look for the camera part, I also have that, I don't know the fix directly but atleast I always know where to look (that differ a lot from not having a clue whatsoever). And you're welcome, programming is indeed a subject that can only be discussed with people that are a programmer. people who are not will either not get it at all or totally overflow immediately by the amount of "unknown" information they have heard just now hehe
I'm always active in this forum so if you open up a new thread ill be there
solved?
broodplank1337 said:
Oh ok nice, I actually thought you had that working already since it was pretty easy to find
Nice that you found it! the isSecure string returned this for me:
Code:
[email protected] /media/broodplank/linuxdata/AOSP-KK/frameworks/base/packages $ grep -r 'isSecure' ../Keyguard/src/com/android/keyguard/KeyguardService.java: public boolean isSecure() {
./Keyguard/src/com/android/keyguard/KeyguardService.java: return mKeyguardViewMediator.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: mShowing = (mUpdateMonitor.isDeviceProvisioned() || mLockPatternUtils.isSecure())
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (mScreenOn && mLockPatternUtils.isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: public boolean isSecure() {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: return mLockPatternUtils.isSecure()
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: if (isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
./Keyguard/src/com/android/keyguard/KeyguardViewMediator.java: return mKeyguardDonePending || !isSecure();
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (lockPatternUtils.isSecure()) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: boolean isSecure = lockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (!isSecure || showsWhileLocked) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: if (!isSecure) {
./Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java: return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
./Keyguard/src/com/android/keyguard/EmergencyButton.java: enabled = mLockPatternUtils.isSecure();
./Keyguard/src/com/android/keyguard/KeyguardSelectorView.java: boolean secureCameraDisabled = mLockPatternUtils.isSecure()
./Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java: public boolean isSecure() {
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: public boolean isSecure() {
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: return service.isSecure();
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: Slog.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
./SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java: Slog.w(TAG, "isSecure(): NO SERVICE!");
./SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java: && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
Great!
Also good that you know where to look for the camera part, I also have that, I don't know the fix directly but atleast I always know where to look (that differ a lot from not having a clue whatsoever). And you're welcome, programming is indeed a subject that can only be discussed with people that are a programmer. people who are not will either not get it at all or totally overflow immediately by the amount of "unknown" information they have heard just now hehe
I'm always active in this forum so if you open up a new thread ill be there
Click to expand...
Click to collapse
This says solved? Is there a download avaliable? I really miss this. Thanks
DrUnkeN_TiGeR said:
This says solved? Is there a download avaliable? I really miss this. Thanks
Click to expand...
Click to collapse
Its an xposed module. Search for it. This thread is discussion, not releasing
The only exposed module I can find is for 4.3 not 4.4.2 could you point me in the right direction?
Sent from my SM-N900V using Tapatalk
DrUnkeN_TiGeR said:
The only exposed module I can find is for 4.3 not 4.4.2 could you point me in the right direction?
Sent from my SM-N900V using Tapatalk
Click to expand...
Click to collapse
All you had to do was click my profile and see the recent threads i've created
http://forum.xda-developers.com/xpo...gmultiplewidgets-kitkat-t2690190/post53476720
Related
[Q] Android Java/Development - WebView findall function
Hello all, Frankly I am not sure that this even belongs here but I think its the closest fit to the forum that I am seeking. If there is a community better suited to answer this please direct me there I have a question about the findall function in webviews. I know that it is deprecated, in eclipse this comes up "The method findAll(String) from the type WebView is deprecated". This is the code I have: Code: public boolean onKey(View v, int keyCode, KeyEvent event) { if ((event.getAction() == KeyEvent.ACTION_DOWN) && ((keyCode == KeyEvent.KEYCODE_ENTER))) { wv.findAll(findBox.getText().toString()); try { Method m = WebView.class.getMethod("setFindIsUp", Boolean.TYPE); m.invoke(wv, true); } catch (Exception ignored) { } } return false; } I just want to have a functioning find/search in a webview. So far this functions great for only some versions of android, versions such as 4.0, 4.0.3, and I believe 3.0 do not function correctly. Older versions of android such as the 2.x series and my nexus s on 4.1 work great. Anyone know of a workaround for a webview function to work on all android versions? If there is something completely different form this I am willing to listen, at this point I only am looking for a functioning search on all versions. Thanks everybody!
how to Provide intent for cards
How to give intent for accessing card activity,its not taking usual class. Below is code snippet im providing. can anyone provide me solution actually im developing simple app for kitkat android mobile.this app is just to access list thats why im using cards. public void onClick(View v) { if(txtUsername.getText().toString().equals("test") && txtPassword.getText().toString().equals("1234")){ Toast.makeText(getApplicationContext(), "Credentials Accepted", Toast.LENGTH_SHORT).show(); Intent i = new Intent(Login_activity.this, HelloCardActivity.class); //hellocardactivity is another card activity. and login_activity is login page startActivity(i); Login_activity.this.finish(); } else{ Toast.makeText(getApplicationContext(), "Wrong Credentials", Toast.LENGTH_SHORT).show(); } } pls provide a solution thank you
How Do I Get ContentResolver Query To Check if Events Exists In The Calendar Or Not?
I need help with this code that I've been trying to figure out for hours. I know it's something close to what I have from my research, but I can't get it to work. Not even the codes provided from other posts on other sites. Any ideas? public void checkEventsInCal() { ContentResolver cr = getContentResolver(); Cursor cursor = cr.query(Uri.parse("content://com.android.calendar/events"), new String[]{"_id"}, "_id=?", new String[]{CalendarContract.Events.TITLE}, null); if (cursor.moveToFirst()) { Toast.makeText(this,"Event Exists!", Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"Event Doesn't Exist!", Toast.LENGTH_SHORT).show(); } } Thanks in advance for your help!!
Can I get a working solution please. Someone please respond. Thanks!
How to make your own music player using HMS Audio Kit: Extensive Tutorial Part 1
More information like this, you can visit HUAWEI Developer Forum Original link:https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201327649924660033&fid=0101187876626530001 { "lightbox_close": "Close", "lightbox_next": "Next", "lightbox_previous": "Previous", "lightbox_error": "The requested content cannot be loaded. Please try again later.", "lightbox_start_slideshow": "Start slideshow", "lightbox_stop_slideshow": "Stop slideshow", "lightbox_full_screen": "Full screen", "lightbox_thumbnails": "Thumbnails", "lightbox_download": "Download", "lightbox_share": "Share", "lightbox_zoom": "Zoom", "lightbox_new_window": "New window", "lightbox_toggle_sidebar": "Toggle sidebar" } If you have always wanted to make your own music player somewhere inside of you, this tutorial is for you. We will use Huawei’s relatively new AudioKit to develop one and I will show the steps one by one so that you can develop a music player on your own. Do not rely on copy-pastes though, I am here to guide you, not let you copy-paste my code. To do that, you do not have to read this extensive tutorial, just click here to reach the full source code. Keep in mind that this source code contains three other HMS kits and their imperfect implementations, it is not a dedicated AudioKit-only app. However, if you are here to learn for real, let’s start below. First of all, make sure you have everything you needed before starting to develop your app. Hardware Requirements A computer (desktop or laptop) running Windows 7 or Windows 10 A Huawei phone (with the USB cable), which is used for debugging Software Requirements Java JDK (JDK 1.7 is recommended.) Android Studio 3.X SDK Platform 19 or later Gradle 4.6 or later HMS Core (APK) 5.0.0.300 or later Required Knowledge Android app development basics Android app development multithreading Secondly, you should integrate Huawei HMS Core to your app. Details are listed here, in the official documentation. You should complete #3 and #4 until “Writing the Code” part. From now on, I will assume that you have prepared your application and ready to go with necessary devices attached for running. Apart from this tutorial, you can always use sample app provided by Huawei, by clicking here. Source code gives idea about most concepts but it is not well-explained and the code is kind of confusing. My tutorial will also use that sample app but it will not be the same thing at all. For app resources like play button, pause button, skip button etc., please find your own resources or use the resources provided by Huawei sample app that I provided the link above. If you already have resources available, you can use them too because it is very important to have a responsive UI to track music changes, but ultimately it does not matter how they actually look. From now on, I will also assume that you have necessary drawables/images/buttons for a standard music player. If you are going to use the app for commercial purposes, make sure the resources you use have no copyright issues. End Product If you want to know what kind of product we will be having in the end, look no further. The below screenshot roughly describes our end product after this relatively long tutorial. Of course, all customizations and UI elements (including colors) are up to you, so it could differ from my product. Also, as you can see my app contains AdsKit and Account Kit usages, which will not be included in this tutorial. That’s why, I will not give you the XML codes of my application (I already shared the my GitHub project link, if you are so inclined). Remark: I mostly use the words audio file, music file and song(s) interchangably. Please do not get confused. Let’s Plan! Let’s plan together. We want to develop a music player application, so it should has some basic features that we want to support, such as play/pause, next/previous audio and seekbar updates. Seekbar will be showing us the progress of the music and it should be updated real time so that our music playback is always synced with life cycles of the app as well as the seekbar of our app. If you want to go further, we should add play modes, shuffle audio files, normal mode (sequential playback), loop the audio and loop the playlist. Of course, we want to render our cover image to the screen for a nice user experience and print the details of the audio file below it. And since we are only implementing the core features, we should have a playlist icon to open up the playlist and we should be able to choose an audio file from it. For the sake of simplicity, all browsed audio files from the device will be added to one single playlist for users to choose from. For the scope of this tutorial, creating new playlists, adding/removing files to those lists etc. are not supported. As can be predicted, our code will include a lot of button clicks. I suggest you start with design on your own. Assuming that you have button/image resources you can imitate the design of my app (screenshot above) or your favorite music player. I placed the playlist button right above and clicking on it should open the playlist, and re-clicking should close it back. You can ignore the test ad below the playback buttons and AccountKit related parts above the cover image. Let me remind you that I use view binding, so it is natural that you will not see much “findViewById”s. For official documentation of what I do, follow here. Let’s code! We should initialize our AudioKit managers to manage the playback later. Then, we should browse the local storage and get the audio files. After also completing listeners and notifications, we should implement button clicks so that users could have a smooth experience. Let’s start with a custom method called initializeManagerAndGetPlayList(…) to do the actual work, it is to be called in onCreate of the activity. Code: @SuppressLint("StaticFieldLeak") public void initializeManagerAndGetPlayList(final Context context) { new AsyncTask() { @Override protected Void doInBackground(Void... voids) { HwAudioPlayerConfig hwAudioPlayerConfig = new HwAudioPlayerConfig(context); HwAudioManagerFactory.createHwAudioManager(hwAudioPlayerConfig, new HwAudioConfigCallBack() { @RequiresApi(api = Build.VERSION_CODES.R) @Override public void onSuccess(HwAudioManager hwAudioManager) { try { mHwAudioManager = hwAudioManager; mHwAudioPlayerManager = hwAudioManager.getPlayerManager(); mHwAudioConfigManager = hwAudioManager.getConfigManager(); mHwAudioQueueManager = hwAudioManager.getQueueManager(); playList = getLocalPlayList(MainActivity.this); if (playList.size() > 0) { Collections.sort(playList, new Comparator() { @Override public int compare(final HwAudioPlayItem object1, final HwAudioPlayItem object2) { return object1.getAudioTitle().compareTo(object2.getAudioTitle()); } }); } doListenersAndNotifications(MainActivity.this); } catch (Exception e) { Log.e("TAG", "player init fail", e); } } @Override public void onError(int errorCode) { Log.e("TAG", "init err:" + errorCode); } }); return null; } @Override protected void onPostExecute(Void aVoid) { PlaylistAdapter playlistAdapter = new PlaylistAdapter(playList); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(MainActivity.this); binding.playlistRecyclerView.setLayoutManager(layoutManager); playlistAdapter.setOnItemClickListener(MainActivity.this); binding.playlistRecyclerView.setAdapter(playlistAdapter); super.onPostExecute(aVoid); } }.execute(); } Let me explain what we do here. We need a thread operation to create the managers and get the configuration in AudioKit. Thus, I used AsyncTask to do just that. Remark: AsyncTask is currently deprecated so I would suggest you to use other methods if you care about modernity. If AsyncTask succeeds, then I get my HwAudioManager instance and set it to my global variable. After that, using that manager instance, I get my player and queue managers. (and config manager as well but it will be used less frequently) After getting my managers, I get my local playlist by a method I will share below. The collections code is just to sort the list alphabetically, you do not have to use it. Later, there is another method called doListenersAndNotifications(…), to set the notification bar and to attach the listeners, which is a crucial part in playback management. In onPostExecute method, now that my managers are ready, I set my adapter for my playlist. However, we will get back to this later on. You do not need to worry about for now. Let’s see how getLocalPlayList(…) works. Beware: In order for below method to work, you must ask for the storage permission from the user explicitly. How to deal with it is your own responsibility. You must consider all cases (like user not giving consent etc.). The below method will work only after the storage permission is granted. Code: public List getLocalPlayList(Context context) { List playItemList = new ArrayList<>(); Cursor cursor = null; try { ContentResolver contentResolver = context.getContentResolver(); if (contentResolver == null) { return playItemList; } String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0"; cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, selection, null, MediaStore.Audio.Media.TITLE); HwAudioPlayItem songItem; if (cursor != null) { if(!cursor.moveToNext()){ //there is no music, do sth return playItemList; //return empty list for now } else{ while(cursor.moveToNext()) { String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); if (new File(path).exists()) { songItem = new HwAudioPlayItem(); songItem.setAudioTitle(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME))); songItem.setAudioId(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)) + ""); songItem.setFilePath(path); songItem.setOnline(0); songItem.setIsOnline(0); songItem.setDuration(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION))); songItem.setSinger(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))); playItemList.add(songItem); } } } } else{ Toast.makeText(this, "We have a serious cursor problem here!", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Log.e("TAG,", "EXCEPTION", e); } finally { if (cursor != null) { cursor.close(); } } Log.i("LOCALITEMSIZE", "getLocalPlayList: " + playItemList.size()); return playItemList; } HwAudioPlayItem is the AudioKit’s POJO class for audio files. It contains the basic attributes of an audio file that developers can set, to use them later. Please note that, as of the publish time of this article, HwAudioPlayItem does not contain enough methods to initialize. Thus, some of the fields you consider you would use may be lacking. For example, there is no field for album name and thus my screenshot above always displays “Album Unknown”. By this method, we browse the local music files, retrieve them in the format of HwAudioPlayItem and add them to a local list. Before returning, see the size of it in the logs. Our playlist is therefore ready, after this operation. Now let’s see how I set listeners and implement notifications. Code: private List mTempListeners = new CopyOnWriteArrayList<>(); //a global variable private void doListenersAndNotifications(final Context context) { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { for (HwAudioStatusListener listener : mTempListeners) { try { mHwAudioManager.addPlayerStatusListener(listener); } catch (RemoteException e) { Log.e("TAG", "TAG", e); } } mHwAudioConfigManager.setSaveQueue(true); mHwAudioConfigManager.setNotificationFactory(new INotificationFactory() { @Override public Notification createNotification(NotificationConfig notificationConfig) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { builder = new NotificationCompat.Builder(getApplication(), null); RemoteViews remoteViews = new RemoteViews(getApplication().getPackageName(), R.layout.notification_player); builder.setContent(remoteViews); builder.setSmallIcon(R.drawable.icon_notifaction_music); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); builder.setCustomBigContentView(remoteViews); NotificationUtils.addChannel(getApplication(), NotificationUtils.NOTIFY_CHANNEL_ID_PLAY, builder); boolean isQueueEmpty = mHwAudioManager.getQueueManager().isQueueEmpty(); Bitmap bitmap; bitmap = notificationConfig.getBitmap(); setBitmap(remoteViews, bitmap); boolean isPlaying = mHwAudioManager.getPlayerManager().isPlaying() && !isQueueEmpty; remoteViews.setImageViewResource(R.id.image_toggle, isPlaying ? R.drawable.ic_notification_stop : R.drawable.ic_notification_play); HwAudioPlayItem playItem = mHwAudioManager.getQueueManager().getCurrentPlayItem(); remoteViews.setTextViewText(R.id.text_song, playItem.getAudioTitle()); remoteViews.setTextViewText(R.id.text_artist, playItem.getSinger()); remoteViews.setImageViewResource(R.id.image_last, R.drawable.ic_notification_before); remoteViews.setImageViewResource(R.id.image_next, R.drawable.ic_notification_next); remoteViews.setOnClickPendingIntent(R.id.image_last, notificationConfig.getPrePendingIntent()); remoteViews.setOnClickPendingIntent(R.id.image_toggle, notificationConfig.getPlayPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.image_next, notificationConfig.getNextPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.image_close, getCancelPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.layout_content, getMainIntent()); return builder.build(); } else{ NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplication(), null); RemoteViews remoteViews = new RemoteViews(getApplication().getPackageName(), R.layout.statusbar); builder.setContent(remoteViews); builder.setSmallIcon(R.drawable.icon_notifaction_music); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); builder.setCustomBigContentView(remoteViews); NotificationUtils.addChannel(getApplication(), NotificationUtils.NOTIFY_CHANNEL_ID_PLAY, builder); boolean isQueueEmpty = mHwAudioManager.getQueueManager().isQueueEmpty(); Bitmap bitmap; bitmap = notificationConfig.getBitmap(); setBitmap(remoteViews, bitmap); boolean isPlaying = mHwAudioManager.getPlayerManager().isPlaying() && !isQueueEmpty; remoteViews.setImageViewResource(R.id.widget_id_control_play, isPlaying ? R.drawable.notify_btn_pause_selector : R.drawable.notify_btn_play_selector); HwAudioPlayItem playItem = mHwAudioManager.getQueueManager().getCurrentPlayItem(); remoteViews.setTextViewText(R.id.trackname, playItem.getAudioTitle()); remoteViews.setTextViewText(R.id.artistalbum, playItem.getSinger()); remoteViews.setImageViewResource(R.id.widget_id_control_prev, R.drawable.notify_btn_close_selector); remoteViews.setImageViewResource(R.id.widget_id_control_next, R.drawable.notify_btn_next_selector); remoteViews.setOnClickPendingIntent(R.id.widget_id_control_prev, getCancelPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.widget_id_control_play, notificationConfig.getPlayPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.widget_id_control_next, notificationConfig.getNextPendingIntent()); remoteViews.setOnClickPendingIntent(R.id.statusbar_layout, getMainIntent()); return builder.build(); } } }); } }); } private void setBitmap(RemoteViews remoteViews, Bitmap bitmap) { HwAudioPlayItem tmpItem = mHwAudioQueueManager.getCurrentPlayItem(); Bitmap imageCoverOfMusic = getBitmapOfCover(tmpItem); if(imageCoverOfMusic != null){ Log.i("TAG", "Notification bitmap not empty"); remoteViews.setImageViewBitmap(R.id.image_cover, imageCoverOfMusic); } else{ if (bitmap != null) { Log.i("TAG", "Notification bitmap not empty"); remoteViews.setImageViewBitmap(R.id.image_cover, bitmap); } else { Log.w("TAG", "Notification bitmap is null"); remoteViews.setImageViewResource(R.id.image_cover, R.drawable.icon_notifaction_default); } } } private Bitmap getAlbumImage(String path) { try{ android.media.MediaMetadataRetriever mmr = new MediaMetadataRetriever(); mmr.setDataSource(path); byte[] data = mmr.getEmbeddedPicture(); if (data != null) return BitmapFactory.decodeByteArray(data, 0, data.length); } catch (Exception e) { e.printStackTrace(); return null; } return null; } public Bitmap getBitmapOfCover(HwAudioPlayItem currItem){ if(currItem != null) { String currentSongPath = currItem.getFilePath(); if (currentSongPath != null) { Bitmap tmpMap = getAlbumImage(currentSongPath); binding.albumPictureImageView.setImageBitmap(tmpMap); return tmpMap; } } return null; } private PendingIntent getCancelPendingIntent() { Log.i("TAG", "getCancelPendingIntent"); Intent closeIntent = new Intent("com.menes.audiokittryoutapp.cancel_notification"); closeIntent.setPackage(getApplication().getPackageName()); return PendingIntent.getBroadcast(getApplication(), 2, closeIntent, PendingIntent.FLAG_UPDATE_CURRENT); } private PendingIntent getMainIntent() { Intent intent = new Intent("android.intent.action.MAIN"); intent.addCategory("android.intent.category.LAUNCHER"); intent.setClass(getApplication().getBaseContext(), MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); return PendingIntent.getActivity(getApplication(), 0, intent, 0); } Let me explain here. I know it looks complicated but most of it is almost copy-paste boiler plate code. First we attach listeners in a looper, HwAudioStatusListener is AudioKit’s listener class. After that we save our queue and set the notification bar. I use this code with else part almost commented out due to support issues but you may copy and paste it to try it out in lower versions of Android. That being said, it should be clear that you should update the resource names as per your needs/wants. setBitmap(…) method is to render the cover image in notification bar layout. (You can find the customized layout in GitHub link I shared). You cannot find this method in this way in sample apps. It is a cool and important feature, so I suggest you use it. Also, there is a NotificationUtils class for additional notification bar related codes, and you may also find it in the GitHub. You do not have to put them separately, you can copy those code to MainActivity and still use them, if you think that that will not be overcomplicating your code. Also the other Bitmap methods will let you use the setBitmap(…) method correctly. Also, they will be useful when rendering the cover image to main screen too. Since HwAudioPlayItem class do not have a field for image paths for easy renders, I had to use more than 2 methods to use the path of the song to retrieve the cover image and then use it to get the Bitmap of it. Other intent methods are to implement the feature of close button to cancel the notification and for the main intent. The End for now! The rest of the application will be talked about in Part 2 of this series. We will be implementing onCreate method, button clicks and listeners in detail. See you there.
[APP][XPOSED][7.0+] WeiJu2 - Scriptable Xposed Module
{ "lightbox_close": "Close", "lightbox_next": "Next", "lightbox_previous": "Previous", "lightbox_error": "The requested content cannot be loaded. Please try again later.", "lightbox_start_slideshow": "Start slideshow", "lightbox_stop_slideshow": "Stop slideshow", "lightbox_full_screen": "Full screen", "lightbox_thumbnails": "Thumbnails", "lightbox_download": "Download", "lightbox_share": "Share", "lightbox_zoom": "Zoom", "lightbox_new_window": "New window", "lightbox_toggle_sidebar": "Toggle sidebar" } The first scriptable xposed module, provides a new way to change the application behavior. Powered by Lua and made with ♥ Features Lua scripting Simple and intuitive hook API Share your package with others by publish it at WeiJu2-Scripts Q&AHow to write a hook? Code: local Toast = import("android.widget.Toast") local Activity = import("android.app.Activity") local Bundle = import("android.os.Bundle") local StringBuilder = import("java.lang.StringBuilder") hook { class = Activity, returns = void, method = "onCreate", params = { Bundle }, after = function(this, params) -- This will call the `StringBuilder(CharSequence seq)` constructor -- to instantiate a StringBuilder object local sb = StringBuilder("Hello, ") sb:append("WeiJu2") Toast:makeText(this, sb:toString(), Toast.LENGTH_SHORT):show() -- ^ -- Note: `this` is the Activity instance end, } How to modify class fields? Code: -- With the `import` function you can bind any java class, and access all the fields and methods that defined -- in that class. No more `XposedHelper.setStaticObjectField(Build.class, "DEVICE", "coral")` much cleaner! local Build = import("android.os.Build") Build.DEVICE = "coral" Build.PRODUCT = "coral" Build.MODEL = "Google Pixel 4XL" Build.BRAND = "google" Build.MANUFACTURER = "google" Build.VERSION.RELEASE = "13" How to import a package? Code: require("ikws4.system_variable").setup { -- configs goes here } How to create a package? A basic package template: Code: --[[ @metadata return { name = "my_package", author = "you", version = "1.0.0", description = "Describle your package" } @end --]] local config = { } local M = {} M.setup = function(opts) config = table.extend(config, opts or {}) end return M Want to share your work with others? Create a PR at WeiJu2-Scripts Screenshots Video guide DownloadGithub release: nightly build
zhipingne said: scriptable xposed module Click to expand... Click to collapse Looks good i wish you good luck
Hi @zhipingne Since from what i understand, it is possible to inject Lua code via Xposed with your application, in your opinion would it be possible to act on all applications embedding web browsers to navigate on web pages adapted to mobiles? Example: inject CSS rules globally on all user applications to affect some like Spotify, Discord, Teams and others? If it's possible I'll have fun!
Rom said: Hi @zhipingne Since from what i understand, it is possible to inject Lua code via Xposed with your application, in your opinion would it be possible to act on all applications embedding web browsers to navigate on web pages adapted to mobiles? Example: inject CSS rules globally on all user applications to affect some like Spotify, Discord, Teams and others? If it's possible I'll have fun! Click to expand... Click to collapse Sorry for the late response, I was experiment a way to inject custom css into WebView in the last two days, And finally got a working demo. (It took so mush time because of the `object` function, in order to proxy a concrete class we need to generate dex file at runtime lol) FYI, I followed this article: https://medium.com/@fanisveizis/usi...d-js-scripts-on-android-webviews-6da0502d6595 UPDATE It stop working... The `dex` file that generate at runtime does not loaded back properly in the next launch time.
zhipingne said: Sorry for the late response, I was experiment a way to inject custom css into WebView in the last two days, And finally got a working demo. (It took so mush time because of the `object` function, in order to proxy a concrete class we need to generate dex file at runtime lol) FYI, I followed this article: https://medium.com/@fanisveizis/usi...d-js-scripts-on-android-webviews-6da0502d6595 UPDATE It stop working... The `dex` file that generate at runtime does not loaded back properly in the next launch time. Click to expand... Click to collapse Ok, do you think it is possible to achieve something functional in the end? I would be very interested. Thx
Rom said: Ok, do you think it is possible to achieve something functional in the end? I would be very interested. Thx Click to expand... Click to collapse Yes, I think it's possible
When i think about it, in fact your module can become as powerful as substratum if we want?
Code: { "builtin": false, "collection": "Privacy", "group": "Use.Tracking", "name": "DeviceIntegrityCheck\/checkIntegrity", "author": "B!", "version": 0, "description": "Skip asitplus device integrity check", "className": "at.asitplus.utils.deviceintegrity.DeviceIntegrityCheck", "methodName": "checkIntegrity", "parameterTypes": [], "returnType": "void", "minSdk": 1, "maxSdk": 999, "minApk": 0, "maxApk": 2147483647, "enabled": true, "optional": false, "usage": true, "notify": false, "luaScript": "function before(hook, param)\n param:setResult(nil)\n return true\nend\n" } (Thanks to B!GBOY) Is it possible to run such a XPrivacyLua script? If so, how formatted?
maxafe said: Code: { "builtin": false, "collection": "Privacy", "group": "Use.Tracking", "name": "DeviceIntegrityCheck\/checkIntegrity", "author": "B!", "version": 0, "description": "Skip asitplus device integrity check", "className": "at.asitplus.utils.deviceintegrity.DeviceIntegrityCheck", "methodName": "checkIntegrity", "parameterTypes": [], "returnType": "void", "minSdk": 1, "maxSdk": 999, "minApk": 0, "maxApk": 2147483647, "enabled": true, "optional": false, "usage": true, "notify": false, "luaScript": "function before(hook, param)\n param:setResult(nil)\n return true\nend\n" } (Thanks to B!GBOY) Is it possible to run such a XPrivacyLua script? If so, how formatted? Click to expand... Click to collapse Code: local DeviceIntegrityCheck = import("at.asitplus.utils.deviceintegrity.DeviceIntegrityCheck") hook { class = DeviceIntegrityCheck, returns = void, method = "checkIntegrity", before = function(this, params) return nil end } Maybe, I can write a convertor for this.
@zhipingne Awesome. Worked right away. Thank you very much!
The version is not available...
xerel89 said: The version is not available... Click to expand... Click to collapse I'm sorry for the late response. What do you mean not available? Is it can not be downloaded? If so, here is the google drive link https://drive.google.com/file/d/1upurJDTJ5nS3RodsqLTCJKFg9daN4EaH/view?usp=sharing
zhipingne said: I'm sorry for the late response. What do you mean not available? Is it can not be downloaded? If so, here is the google drive link https://drive.google.com/file/d/1upurJDTJ5nS3RodsqLTCJKFg9daN4EaH/view?usp=sharing Click to expand... Click to collapse Thank you for this module, it looks awesome! Do you think it would be possible to use it to implement java code, such as a java script to disable the elastic overscroll in Android 12+? There is an example in java located here that I would like to test. https://github.com/ionic-team/capacitor/issues/5384
jal3223 said: Thank you for this module, it looks awesome! Do you think it would be possible to use it to implement java code, such as a java script to disable the elastic overscroll in Android 12+? There is an example in java located here that I would like to test. https://github.com/ionic-team/capacitor/issues/5384 Click to expand... Click to collapse Yes, you can translate java code in to WeiJu2 scripts, here is an example: Code: local BridgeActivity = import("com.getcapacitor.BridgeActivity") hook { class = BridgeActivity, returns = void, method = "onStart", after = function(this, params) local webview = this:getBridge():getWebView(); webview:setOverScrollMode(webview.OVER_SCROLL_NEVER); end } Note: I did't test the code, it just an example to show it's possible to implement java code using WeiJu2 hook. UPDATE How to disable Programmatically Android 12 Elastic Scroll Animation how can I turn off the elastic scroll effect that comes with android 12? Best regards stackoverflow.com https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/View.java;drc=c645853ab73ac8c5889b42f4ce7dc9353ee8fd35;bpv=1;bpt=1;l=3657 I think this code will make all view non over scrollable. Code: local View = import("android.view.View") hook { class = View, returns = void, method = "setOverScrollMode", before = function(this, params) local OVER_SCROLL_NEVER = 2 params[1] = OVER_SCROLL_NEVER end }
zhipingne said: Yes, you can translate java code in to WeiJu2 scripts, here is an example: Code: local BridgeActivity = import("com.getcapacitor.BridgeActivity") hook { class = BridgeActivity, returns = void, method = "onStart", after = function(this, params) local webview = this:getBridge():getWebView(); webview:setOverScrollMode(webview.OVER_SCROLL_NEVER); end } Note: I did't test the code, it just an example to show it's possible to implement java code using WeiJu2 hook. UPDATE How to disable Programmatically Android 12 Elastic Scroll Animation how can I turn off the elastic scroll effect that comes with android 12? Best regards stackoverflow.com https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/View.java;drc=c645853ab73ac8c5889b42f4ce7dc9353ee8fd35;bpv=1;bpt=1;l=3657 I think this code will make all view non over scrollable. Code: local View = import("android.view.View") hook { class = View, returns = void, method = "setOverScrollMode", before = function(this, params) local OVER_SCROLL_NEVER = 2 params[1] = OVER_SCROLL_NEVER end } Click to expand... Click to collapse Thank you for the reply. That's awesome to hear. I'm going to keep messing around with it to see if I can disable the overscroll then. The code that you provided unfortunately doesn't work for all apps. It does work for some however. I believe there is another hook somewhere that must be disabled as well. If you have any ideas they would be greatly appreciated. Thank you again for the app. It's amazing!
jal3223 said: Thank you for the reply. That's awesome to hear. I'm going to keep messing around with it to see if I can disable the overscroll then. The code that you provided unfortunately doesn't work for all apps. It does work for some however. I believe there is another hook somewhere that must be disabled as well. If you have any ideas they would be greatly appreciated. Thank you again for the app. It's amazing! Click to expand... Click to collapse Try this to see if it works Code: local View = import "android.view.View" local OVER_SCROLL_NEVER = 2 hook { class = View, params = { Context, AttributeSet, int, }, after = function(this, params) this.mOverScrollMode = OVER_SCROLL_NEVER end, } hook { class = View, returns = void, method = "setOverScrollMode", before = function(this, params) params[1] = OVER_SCROLL_NEVER end, }
zhipingne said: Try this to see if it works Code: local View = import "android.view.View" local OVER_SCROLL_NEVER = 2 hook { class = View, params = { Context, AttributeSet, int, }, after = function(this, params) this.mOverScrollMode = OVER_SCROLL_NEVER end, } hook { class = View, returns = void, method = "setOverScrollMode", before = function(this, params) params[1] = OVER_SCROLL_NEVER end, } Click to expand... Click to collapse Thank you for the attempt, but unfortunately, that doesn't seem to fix it either. I've asked multiple developers to see if they could sort it and nobody has been able to so far. I don't know how Google implemented it so deep, but it seems very difficult to remove the "accordion" scroll. Thank you for trying though. If you have any ideas though, they would be greatly appreciated.
zhipingne said: I'm sorry for the late response. What do you mean not available? Is it can not be downloaded? If so, here is the google drive link https://drive.google.com/file/d/1upurJDTJ5nS3RodsqLTCJKFg9daN4EaH/view?usp=sharing Click to expand... Click to collapse Thanks! The apk isn't posted on the first post or on github. This does seem like a replacement for XprivacyLua which just stopped being supported.
It work perfectly! Thank you very much. One more thing, Is there a way we can load script from local file instead of write directly on module interface, please?
wanting2521 said: It work perfectly! Thank you very much. One more thing, Is there a way we can load script from local file instead of write directly on module interface, please? Click to expand... Click to collapse File access causes me a lot of headache, and current implementation still have some flaw it. Why would want load script from file? ref: https://github.com/ikws4/WeiJu2/issues/7#issuecomment-1248109818