Cannot Import Google Platform (AOSP) App's Java File to Android SystemUI Java File. - Android Software/Hacking General [Developers Only]

Hi all,
Excited to be a new member to this forum, seems like there is lots of powerful information here.
So, not the most clear title ever, but a specific example of my problem goes like this. If I want to take advantage of googles launcher3 src code such as CellLayout.java (packages/apps/Launcher3/src/com/android/launcher3/CellLayout.java) so I can play with the ability to reorganize the home screens app layout using the methods existing in that file. I would wish to import this CellLayout.java file so I can use it from a quick setting tile button's file, such as in the airplane mode tile.
In file frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
So if I add the line "import com.android.launcher3.CellLayout;" in AirplaneModeTile.java, when I do a full AOSP build with the changes to the two files I get a compile time Error on the import code that "launcher3 cannot be resolved".
If I had to guess these two files are in different domains of sorts, and I think when I build using GNU make from the top directory, the Google App's code (h t tps:// android.googlesource. c o m /platform/packages/apps/) such as the AlarmClock, Contacts, Camera, and Launcher3 for example are built and then removed from scope at a different time than the Android systemui code.
Any thoughts on how to fix this?

Related

[Q] To which language does the following code belong to ?

Hey Guys,
Recently I was planning to learn to code android apps, so I decompiled an app I wanted to modify & was going through the source code. All of the .smali files were un-encrypted. I would like to know if this code is Objective-C or Java.
I tried to add the code snippets & also tried to pastie it but apparently the posts doesn't seem to accept foreign links so I'll try to post it in the comments.
File Names: h, h$a
Also, I wanted to know what do these file names represent & what does the "dollar" sign stand for in the file names.
Thanks in Advance,
Netguy
Update: I tried posting it via comments but it wasn't possible. Let me know how can I share the code over here. Thanks.
Smali is disassembled Dalvik virtual machine byte code.
The source of it is Java, although you can't easily reconstruct the original source.
MyClass.smali is the class file for MyClass
MyClass$SubClass.smali is the class file for the nested subclass SubClass
MyClass$1.smali is the class file for an anonymous nested subclass.
ab.smali and ab$bd.smali are obfuscated file names.
Some companies rename everything using automatic tools to hide the intent.
Yes, you can write in smali if you like.
Usually such use is limited to small changes in an existing program.
Thanks a lot for the information Renate NST. While digging through some of the smali files, I found some URLs related to the google ads. So will changing the URL to something else disable the ads or will it just result in malfunctioning of the app ? Thanks a lot once again.

[App][Code project][5.0+]Rom Control app for devs

Hello ya'all,
This is gonna be a long op, I dunno where to start...
Sooooo... a while ago a friend (@tdunham) asked if we could share a settings app we made for our rom(s) (future rom(s).... as we are lazy bums). Since we mostly aimlessly wander around xda and help other devs instead of releasing our stuff, we figured... what the hell, we might as well make it into a source code project in a java-unexpirienced-dev format. So here we go!
About the project:
This app has a main function of coordinating content resolver entries between user end (your rom control app) and mods end (when you use content resolver to reitrieve settings storage database entry keys in various modded system apps).
Basically, you create a preference item, such as switch preference f.e, and when the user switches it, an entry is being overwritten in Settings.System. From there, your modded apps, according to your mods, can read the value and do some stuff...
Needless to say that this app requires, among many other things, your ability to mod system apps to use content resolver. If this doesn't mean anything to you, you're in a wrong place.
If you wish to learn more about modding smali using content resolver, you need to first get introduced to 2 amazing threads:
1. Creating and Understanding smali mods by @Goldie - if you are not fluent in that thread, you will not need this app.
2. Galaxy s5 unified mods and guides thread by @tdunham - not all guides there are using content resolver, but lately more and more are. In any case it's a great place to ask questions, learn and contribute.
Nuff said about modding, now to the project
Project characteristics:
The project is a source code project. Meaning we are not providing an application and you will not be using it by decompiling it with apktool. There are so many reasons for that that I don't know where to start. Mainly - it's bad enough samsung has made hackers out of all of us and we need to decompile and backdoor their system apps to mod them. What we can provide in source code - we will. We strongly believe in the freedom of code and we share it unconditionally (almost).
Now what is that "almost? part? Simple... You do NOT need to credit us in any of your work, you do NOT need to thank us, you do NOT need to ask permission to use this project in your rom, you also do NOT need to donate to us (you also can't, we don't have a donate button). YOU DO NEED TO RESPECT THE FREEDOM OF CODE! That means that this code is given to you under the GNU GPL (General Public License). You can review it fully here.
The most relevant part to our discussion is as following:
...For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights...
Click to expand...
Click to collapse
That being said, the only thing that is required of you is that you keep sharing the code. We are not going to run around xda and "police" people using the code and not providing source. We rely on your word, that by agreeing to use the open source, you will keep it public and provide your sources as well for others to use. This VOIDS xda rule number 12, stating that each dev owns their work. Becasue the rule also states that work that is provided by a lisence that negates exclusivity, is therefore not exclusive. Any work based on this code is not to be held exclusive. And if another developer wants to use an app you built based on this code, you have an obligation to provide your sources and to keep those updated to most recent version of the app you release in order to be compliant.
Thread rules and disclaimaers:
The code is 100% original and written by us (myself and @wuby986) for this specific project. All the classes imported from public open source repositories are annotated with original developer signature and our modifications are annotated and dated as well.
To answer most asked question so far - we don't know how it is different from a custom settings app by ficeto. We have never used it in our roms and we have nerver seen it's code (neither have you). Both apps share the same idea of integrating preferences into settings db using content resolver. You are free to use any app you like. We are not saying which app is better or worse. This is seriously not a competition.
This project requires extensive knowledge in android development. As mentioned above, if you don't know how to mod system, this app is of no use to you. We will not be answering questions about smali mods.
This project requires basic knowledge in operating android studio. You need to have it installed and operational in order to work with the code. You need to have android sdk and all the support libraries updated.
This project requires SOME coding expirience or AT LEAST an open mind to getting a crash course. You will not be required to do heavy java lifting to use this app, but it would help if you knew alittle bit.
We cannot teach you how to use android studio, debug problems related to it and so on. We will provide basic instructions as to how to add items to the navigation drawer list, how to add preference fragments with ease, we will explain the idea of out code and different preferences to you. Beyond that - it's on you. We cannot and will not teach you to be a programmer. If you want to know more - the web is wide and google is your friend.
We cannot debug your code problems. This thread is for development discussion related to the project itself. If you need some requests, questions regarding exsisting code, remarks, improvements, you're more than welcome to join a github project and commit your code for everyone's benefit.
Nuff said about rules, moving forward:
Project sources:
Github source for the Rom Control application is here
Github source for the template to add preference fragment for this specific app is here
Initial instructions:
Download and install Android Studio and android sdk for your platform. Make sure all are updated
Go to the preference fragment repository and download the master as zip. Extract the zip contents into /your android adt directory/android-studio/plugins/android/lib/templates/other/
Reopen android studio
File > New > Project from Version Control > Git
The git repository is https://github.com/daxgirl/CustomSettingsForDevs.git
Specify your parent directory and directory to contain the project (will be suggested by studio)
Clone from git
Done you have the project on your pc. Wait for it to sync and build gradle.
The next couple of posts will explain extensively how to operate the app and create customize it to your rom's needs.
XDA:DevDB Information
[App][Code project][5.0+]Rom Control app for devs, App for all devices (see above for details)
Contributors
daxgirl, wuby986
Version Information
Status: Testing
Current Stable Version: 1.0
Created 2015-06-30
Last Updated 2016-04-12
Basic info and app structure
Basic info and app structure:
This application is Navigation Drawer application material design style. It uses app cpmpat in order to use the pager adapter. This can make theming alittle bit tricky, but we provided 2 themes for now which you can modify in styles.
Navigation drawer opens from the left and it contains for now example of navigation items list. For now we have 4 preference fragments and the last items is to set theme. You can add or remove fragments as you wish. The process will be fully explained.
The fragments in the main view container are being replaced based on a position of clicked item in the navigation drawer list. Remember (we will get back to it again), positions in any array begin from 0. That means that for now we have 0,1,2,3,4 items in the arrays that construct the navigation items list. When we add one, we will need to add a title and an icon (both in corresponding positions) and also add our new fragment to a special method which makes the selected items to show specific fragment. We will discuss it at lenght.
For now application contains only preference fragments. If you feel confident and know what you're doing, you can add all kinda fragments and navigation items (even more activities). We concentrate here on preference fragments, because this is the essence.
Each navigation fragment has a java class which extends PreferenceFragment and an xml file inside res/xml folder, where the preferences exist for each fragment. Once launched for the first time, each fragment will create a shared preferences file inside our "home" directory. Our directory is in /data/data/com.wubydax.romcontrol/. There you will find several files and dirs. One of them is called shared_prefs. Inside it each fragment will host it's preference xml file. The name of this file will be identical (by our design) to the name of the xml file for that fragment in /res/xml folder. Once the fragment displayed for the first time, the shared preferences file for it is created and being populated by the default values you set. We will explain later which preferences must have defaultValue set and which preferences MUST NOT.
If you open the java class for any PreferenceFragment, f.e. UIPrefsFragment.java, you will see that the code is very small. That is because we wanted to make things easier for you and we created a class called HandlePreferenceFragment.java, which manages all the work of the fragments.
When you create a new Preference Fragment using a template for android studio we provided, The fragment and it's xml file are created for you automatically. All you will have to do is add it to the item selector in the navigation drawer, of course give it a name and an icon, and you can gop ahead and populate the xml file with preferences. You will not need to touch java anymore if you don't want to.
We have the usual preferences that you know of, like SwitchPreference, CheckboxPreference, ListPreference etc, and we have our own "special" preferences to make your life easier. Those are IntentDialogPreference (to choose an app and write it's intent to the database for you to use in your mods to open apps), FilePreference (to control some booleans by creating and deleting file), we have 2 special kinds of PreferenceScreens: one for running shell scripts and one for creating intent to open apps from the control app. Those preferences will have special kind of keys, which we will demonstrate. You will not need to flash your scripts when flashing your rom. All your scripts will be managed in the assets folder and copied on run time to our home directory and executed from there. You don't need to worry about permissions, all is taken care of. Just place your scripts inside the assets folder before you compile the sources. Sae thing with opening apps as intents, all you need to do is put a main activity full name as PreferenceScreen key. Everything else is taken care of, including displaying icon. The preference will not show at all if the user doen's have an app installed. So no crashes upon clicking on non existing intents. They will just vanish from the list.
The preference files inside the project on github contains BOGUS preferences to use as an example. We will go over all of them (most contained inside first fragment - UIPrefsFragment). They are all active. But they should not trigger any mod, as you should not have those keys in your database. You can see f.e. that preference fragment "Useful apps" has like 5 preferences for app intent. some of them have bogus intent. They will not display when you run your app. They are therer to demonstrate that if the app doesn't exist, you should not worry about FC of Rom Control. It takes care of itself.
The first time the app boots it asks for root permissions. If the device is not rooted or permissions not granted, the app will never run. You all run rooted and modded roms, this app is not for stock. If you wish to disable this function, we will provide that option.
Reboot menu - on the right upper corner of the action bar you will see a reboot icon. Clicking it will show a display of 5 reboot actions: reboot, hotboot, reboot recovery, reboot download, reboot systemui. Youc an access those easily no matter what fragment you're in. Clicking outside of them or clicking back button will make the menu disappear. clicking on one of them will result in immidiate reboot function. Those are root related finctions. We can make them no root dependant once you all use an app in your /system/priv-app. Which, btw, is where we recommend it goes.
How does it work?
For the first time an app is opened (or any time an ap is opened), there is a special method inside HandlePreferenceFragment that is called initAllKeys();. This method goes over all the preferences contained inside the shared preferences for that fragment. One by one it checks their key name, checks if they are of type boolean (true or false), of tipe integer (number) or of type string (words). Then it checks what preference they belong to. It checks if the key for that preference exists in your settings storage database, if it does not - it creates all keys. If the key exists in the database but is different from what the app has - it replaces the one in the app preferences with what you have in your system. That is why it's important for most preferences to set the defaultValue that you wish to be the default, beucase the first time the app launches, it will create all the keys in the system database. once the process is done(you will not see or feel it), your preferences are yours to control. Once a user clicks on Checkbox, if it's selected (isChecked), it writes 1 to the key for that preference inside the Settings.System. and vice versa. Any change in the preferences is being registered immidiately. So your mods can be updated (provided you have observers, of course, or else you might need to reboot apps, just like you always did). Inside the class HandlePreferenceFragment there is a method updateDatabase. it is being called from a method that "wacthes"/"listens" to any change in preference.
That is, basically, all. This is how it works. Everything else is cosmetics made for your convinience and mostly based on your requests. F.e. running shell scripts, FilePreference, App picker preferences was requested by other developers to be included so we had to find a way to build in. Now you can all enjoy. Any further requests are welcome.
Overall structure in studio:
One you have opened the project in studio, you have the following structure tree on your left. Make sure you have chosen the "project" tab (far left edge of the screen) to see it:
Inside the libs folder we have the roottools jar made by the amazing @Stericson and the next folder that is of interest is the src/main. This is where the app as you know it (from apktool) is hosted. You can see inside the res folder all our resources.
If you need to change the icon for the app you need to place it inside mipmap folders. It's called ic_launcher.png. For nice app icons generator visit here . Inside the values-21 folder there is the styles.xml file that you need to edit if you want to change theme colors. Nice site for coherent material palette is here and google documentation is here.
In the main drawables folder you will find those:
As you can see there are two images there that are relevant to you: header_image and header_image_light (for both themes). Thopse are the header images for the navigation drawer. You can replace them with your own. The reference to them is inside /layout/fragment_navigation_drawer.xml as you can see here:
.
Here it's used as an attribute. You can read more about using attrs in android docs. Just replace the images and keep the names.
Inside of the resolution dependant drawable folders you can find the images for the items in the navigation drawer:
Here you can replace, move and add your own. Good resources for icons are: here and here and you can find many more out there.
Inside the assets folder we have a folder named scripts. It's important the name remains "scripts".
It's used in java code to copy the assets on runtime to our home dir. Inside scripts you put your shell scripts that you wish to run using the script running method. scripts have to be called with .sh in the end. When you create a PreferenceScreen that needs to run scripts, you give it a key like this: android:key = "script#nameofourscript". You do not add the .sh in the key. Look at the example inside ui_prefs.xml in PreferenceScreen with key android:key = "script#test". This runs the script that is currently found in assets. which basically writes into a file on your sdcard. Here you can put scripts as complex a you like. The code checkes for the exit code of the script. as long as it is 0, it will print a toast "executed successfully" upon clicking your preference. To try it run the app on your phone and click on a preference screen with summary "Click see what happens". Make sure your scripts are well formed and test them before including. Remember that you're under sudo. Linux shell will execute anything under sudo without asking.
Inside the /res/xml folder are our preference xml files. This will be your main playground. In those files we will be adding the preference items to appear in each of your fragments.
And finally for the java classes:
Here is where all the work is being done in real time. If you don't have expirience, you won't have to go there besides when you need to add the more nav drawer items.
Adding a new fragment and navigation drawer list item:
1. Provided you read the OP instructions and cloned the Rom Control Preference Fragment template repository into /your android adt directory/android-studio/plugins/android/lib/templates/other/, you need to restart android studio and we are ready to go.
2. Right click on the main java package of out application and navigate to New > Fragment > Fragment (6thGear Preference Fragment) like you can see on the picture below:
Once you click on adding the fragment the foloowing window will open:
As you can see the initial names are: for fragment - BlankFragment and for xml blank_prefs. You can change it as you like. BUT! Leave the word Fragment. Once you change the FIRST part of the fragment name, the first part of the prefs file name will be changed automatically. See the img below:
So we have chosen to create a new fragment called PowerMenuFragent and below that we have the preference xml name. the name is automatically generated as you put in your class name for the fragment. The java naming convention states that a class must begin with capital letter and all meaningful words in class name must also begin with capital letter. The xml name generator will split the word Fragment from your class name and make the other words into xml legal name form separated by under score and will add _prefs in the end. So it becomes power_menu_prefs.xml.
Click "finish" and you have a new fragment class and a new xml file for it inside /xml folder. The fragment will look like this:
You don't need to edit it. It's done in template. It instantiates the class called HandlePreferenceFragment and refers to it's main methods. For more infor you can read my annotations in the HPF class.
Your new xml file is now empty and contains an empty preference screen like so:
We will populate it with preferences later.
Now we need to make this new fragment REACHABLE for user. So we need to add an item to the navigation drawer sections. Let's do that:
1. Open /values/strings.xml and find an array of strings. we will add our new item name in a place we want. In this case I will add it after the Framework section (in blue):
Code:
<string-array name="nav_drawer_items">
<item>SystemUI Mods</item>
<item>Phone Mods</item>
<item>Framework and General</item>
[COLOR="Blue"][B]<item>Power Menu</item>[/B][/COLOR]
<item>Useful Apps</item>
<item>Set Theme</item>
</string-array>
2. Now you will need a new icon to appear to the left of the section name in nav drawer. You can add your own icon at this point. It's a good practice to add images for all resolutions. But who are we kidding? You're making a rom for one device. So to remind you, s4, note3, s5 are xxhdpi and note4, s6 are xxxhdpi. I will use existing icon called ic_reboot.png for this section.
3. Now we need to get our hands dirty and go into java alittle. Open MainViewActivity and find the following method. This method is well annotated for your use. So you can refer to it every time you add an item for reference of how-to. Observe the new blue item:
Code:
//Creates a list of NavItem objects to retrieve elements for the Navigation Drawer list of choices
public List<NavItem> getMenu() {
List<com.wubydax.romcontrol.NavItem> items = new ArrayList<>();
/*String array of item names is located in strings.xml under name nav_drawer_items
* If you wish to add more items you need to:
* 1. Add item to nav_drawer_items array
* 2. Add a valid material design icon/image to dir drawable
* 3. Add that image ID to the integer array below (int[] mIcons
* 4. The POSITION of your new item in the string array MUST CORRESPOND to the position of your image in the integer array mIcons
* 5. Create new PreferenceFragment or your own fragment or a method that you would like to invoke when a user clicks on your new item
* 6. Continue down this file to a method onNavigationDrawerItemSelected(int position) - next method
* 7. Add an action based on position. Remember that positions in array are beginning at 0. So if your item is number 6 in array, it will have a position of 5... etc
* 8. You need to add same items to the int array in NavigationDrawerFragment, which has the same method*/
String[] mTitles = getResources().getStringArray(R.array.nav_drawer_items);
int[] mIcons =
{R.drawable.ic_ui_mods,
R.drawable.ic_phone_mods,
R.drawable.ic_general_framework,
[B][COLOR="Blue"]R.drawable.ic_reboot,[/COLOR][/B]
R.drawable.ic_apps,
R.drawable.ic_settings};
for (int i = 0; i < mTitles.length && i < mIcons.length; i++) {
com.wubydax.romcontrol.NavItem current = new com.wubydax.romcontrol.NavItem();
current.setText(mTitles[i]);
current.setDrawable(mIcons[i]);
items.add(current);
}
return items;
}
As you can see I added a line R.drawable.ic_reboot. What is it? This is an equivalent to public id in smali. It is in fact an integer. So it appears inside integer array called mIcons. Our respurces in android are referenced by capital R. then we have the resource type, in this case - drawable, and then the item name (without extension). Note the order of the id in the array, I added my string after the framework string. So I also add the id for the drawable after the id of the framework drawable. This is vital to understand, as the list is being populated on runtime based on items positions. Items in an array are separated by comma.
4. Now open NavigationDrawerFragment class and you will find the same method there. Please add the same id in the same way there. You MUST do so in both classes every time.
5. Now we go back to the MainViewActivity and we find the following method. it will be right after the getMenu() method we just edited. The method is called onNavigationDrawerItemSelected(int position). This method is responsible for performing action based on which navigation drawer item is clicked by a user. Positions are the positions of items in the List of our objects. So we have so far 6 items out arrays (strings and drawable id integers). That means their positions are 0,1,2,3,4,5 respectively. Look at the method as it appears in the original code:
Code:
@Override
public void onNavigationDrawerItemSelected(int position) {
/* update the main content by replacing fragments
* See more detailed instructions on the thread or in annotations to the previous method*/
setTitle(getMenu().get(position).getText());
switch (position) {
case 0:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new UIPrefsFragment()).commitAllowingStateLoss();
break;
case 1:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new PhonePrefsFragment()).commitAllowingStateLoss();
break;
case 2:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new FrameworksGeneralFragment()).commitAllowingStateLoss();
break;
case 3:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new AppLinksFragment()).commitAllowingStateLoss();
break;
case 4:
showThemeChooserDialog();
break;
}
}
Here we have switch case based on position of an item. This is the same as saying: if the position of an item is 0, perform this action, else, if the position is 1, perform that action and so on. Only in this case we say: compiler, switch cases based on integer - in case 0: do something, in case 1: do something else. So we need to add an item after the framework section. Framework section has position of 2 (it's item number 3). So now we add our new fragment like so:
Code:
@Override
public void onNavigationDrawerItemSelected(int position) {
/* update the main content by replacing fragments
* See more detailed instructions on the thread or in annotations to the previous method*/
setTitle(getMenu().get(position).getText());
switch (position) {
case 0:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new UIPrefsFragment()).commitAllowingStateLoss();
break;
case 1:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new PhonePrefsFragment()).commitAllowingStateLoss();
break;
case 2:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new FrameworksGeneralFragment()).commitAllowingStateLoss();
break;
[COLOR="blue"][B]case 3:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new PowerMenuFragment()).commitAllowingStateLoss();
break;[/B][/COLOR]
case [COLOR="blue"][B]4[/B][/COLOR]:
getFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.container, new AppLinksFragment()).commitAllowingStateLoss();
break;
case [COLOR="blue"][B]5[/B][/COLOR]:
showThemeChooserDialog();
break;
}
}
Note how the new case is now number 3 and the positions of the following cases need to be increased.
Now we can run our app and and there is our new section item:
That's it for this post. Post #3 we will talk about different preference kinds we have and how to use them.
Till then...
To be continued.....​
Handling different kinds of preferences:
Now we roll with populating our preference fragments. Each preference fragment is unique for your needs, depends on your use, your modded apps and categories. All we do, as mentioned above, is provide you with preferences to communicate with your modded system apps using ContentResolver class.
For each preference I will explain:
Does it write preferences into shared preferences? and if it does...
What kind of object it writes to shared preferences of our app?
What kind of value we then write into SettingsSystem database?
What kind of key it uses and why?
SwitchPreference/CheckboxPreference:
Images:
You MUST provide defaultValue for ANY switch preference you create
It writes boolean (true or false) into the shared preferences
We copy it as integer (1 or 0) into the Settings.System database
It mush have a unique key, none of existent in databse. It must be the same key as you use in your mod for that function. F.e. statusbar_clock_visibility. Clock can be either visible or invisible. So switch preference will serve us good here. Also will checkbox preference. In your mod when you retrieve and integer using ContentResolver you specify the default value (if the key is not found). You have to specify the same default value here. If in smaly it was 0x1,. then in the app it must be android:defaultValue = "true". YOU MUST SPECIFY DEFAULT!
In preference xml inside your empty PreferenceScreen claws, you add this:
Code:
<SwitchPreference
android:defaultValue="true"
android:key="clock_visibility"
android:summaryOff="Clock is hidden"
android:summaryOn="Clock is visible"
android:title="Set Clock Visibility" />
Code:
<CheckBoxPreference
android:defaultValue="false"
android:key="brightness_visibility"
android:summaryOff="Brightness slider hidden"
android:summaryOn="Brightness slider is visible"
android:title="Notification Brightness Visibility" />
This is all you need. The key will work automatically. The first time the user runs your app it will look for that key in the database, if it finds it, it will copy the value into our app and the switch will be set accordingly, if it does not find it, it will copy the defaultvalue of your preference to the database.
Of course the proper way of using strings for title and summary is by using string resources. In android studio you can create strings resources after you have typed the string. F.e. click on one of the strings, like for title, and on your keyboard press alt+enter. You will be given an option to extract string resource. That is all up to you. If your app is only in english, you don't really need to do that.
ListPreference:
Usually you would create list preference by specifying <ListPreference..../>. We had added some functionality to native android preferences for List and EditText. So we have our own classes that extend those preferences. So when we create a list preference we use our own class, so the preference looks like this:
Code:
<com.wubydax.romcontrol.prefs.MyListPreference
android:defaultValue="2"
android:entries="@array/clock_position_entries"
android:entryValues="@array/clock_position_values"
android:key="any_clock_position"
android:title="Status Bar Clock Position" />
Once you open < in studio and start typing com..... it will give you the options of preferences existing in our app. Just choose the one you need and it will create the name for it. Don't worry if you mistype, it will not compile.
List preference in android persists string. That means that it writes object of string type into the shared preferences. You need to create 2 string arrays for each list preference. One for Entries - what is displayed in the dialog as single choice items for user. and One is for entryValues (what is being written into the preferences). You can from your mod read them as integers or strings using content resolver. f.e., if your values are 200, 300, 400, android will persist them as strings. But when you restrieve them from database in your systemui smali mod, f.e., you can call either getInt (to get them as integers) or getString to get them as strings. Of course strings array like bread, milk, cookies cannot be retrieved as integer. But a string 200 can be either.
When you retrieve a default value in your smali mod, you retrieve f.e. 200. so YOU NEED TO SET 200 as defaultValue. Or in the above case, it's 2. YOU MUST SPECIFY THE DEFAULT STRING!
You do not specify summary for this preference, we take care of it in code. like so:
EditTextPreference:
Code:
Code:
<com.wubydax.romcontrol.prefs.MyEditTextPreference
android:defaultValue="simpletext"
android:key="carrier_text"
android:title="Set Custom Carrier Text" />
This preference also persists string. It also writes string into the database. You retrieve it only as string. Because you can't control what user types. You don't want your modded systemui to crash because a user inputted "bread" and you are trying to read it as integer.
YOU MUST SPECIFY THE DEFAULT STRING for EditTextPreference.
ColorPickerPreference:
Writes and integer into the sharedpreferences and we retrieve integer into the database.
Color integers are special. I will not go into how and why. I have created a utility helper app for devs for this purpose. The app's main function is to convert hex string to integers or to reverse smali hex string. You can find an apk and explanations how to use it here.
Remember, YOU MUST-MUST-MUST SPECIFY defaultValue for ColorPicker in our app!!! and YOU MUST USE ACTUAL INTEGERS to do so properly. Just trust us on that. It's no biggie. You use our app for hex converter to both create your default smali hex value and to create an integer for this app.
The code for ColorPickerPreference:
Code:
<com.wubydax.romcontrol.prefs.ColorPickerPreference
alphaSlider="true"
android:defaultValue="-16777215"
android:key="clock_color"
android:title="Choose Clock Color" />
As you can see this android:defaultValue="-16777215" is an actual integer for color black. You get it by using our app. You put 000000 into the first text field and click the button. The integer that you get is -16777215. We also have color preview available. It's a very useful tool. Use it and you can never go wrong with neither integers nor smali inverse hex values for your default color.
Now note the special attribute called "alphaSlider" in the code. This is a boolean type. By default it's false. Meaning you can create color picker preference with or withour transparency option.
SeekBarPreference - the SLIDER:
Writes integer of the slideer progress into the database. The moment your finger has stopped tracking the bar, an integer is being registered into the sharedpreference and then being retrieved into the databasse.
Code:
<com.wubydax.romcontrol.prefs.SeekBarPreference
min="0"
unitsRight="Kb/s"
android:defaultValue="10"
android:key="network_traffic_autohide_threshold"
android:max="100"
android:title="Autohide Threshold" />
YOU MUST SET DEFAULT VALUE!!!! IN INTEGER!
You can specify special values such as unitsRight, like "%" or "Kb/s" and so on. You can specify the min and the max value. You probably better not specify the summary. But you can if you want.
IntentDialogPreference - App Chooser:
Code:
<com.wubydax.romcontrol.prefs.IntentDialogPreference
includeSearch="true"
setSeparatorString="\##"
android:key="choosen_app_gear"
android:title="Choose App" />
This is a very special preference kind. It was created by request from @rompnit. They use intents from database to open apps in certain mods. You will have to ask them on @tdunham thread how and when they use it. We created this preference from scratch specifically for them. This is a completely custom kind of android preference. It displays a dialog of all your LAUNCHABLE apps (apps that have default launch intent that can be retrieved by using PackageManager method getLaunchIntentForPackage. In other words - all apps that appear in your launcher will appear on the dialog.
What happens when you click on an app? What is being written into preferences is a special kind of string. The srting might look like this: com.android.settings/com.android.settings.Settings or it might look like this com.android.settings##com.android.settings.Settings... this is what you need to create basic intent. You need package name and activity name. What separates them is up to you. You will need to split them in your smali mod into package name and activity name to create intent. We have created 2 special attributes for this preference:
1. setSeparatorString =this is what will separate the package name from the class name. The default (if you don't specify) is "/". Remember that if you use chars that must be escaped in xml, f.e. like hash(#), you need to escfape them by backslash, like so setSeparatorString = "\##".
2. includeSearch - this is a boolean type of attribute. It is false by default. If you specify true, the search field will appear on the dialog above the apps list, allowing your users to search for an app by name inside the list adapter. We also included a list alphabetical indexer. So it's up to you if it's necessary.
Once the app is chosen, the summary for the preference is set to the app name and the icon on the right side will be the app icon.
Your database will contain now the basic component for the intent. What you do with it in your smali is up to you.
DO NOT SET DEFAULT VALUE FOR THIS PREFERENCE!!!
FilePreference:
This is very special kind of preference requested by @tdunham. What is does it creates and deletes file with a certain name in our home files dir. It is located at /data/data/com.wubydax.romcontrol/files
Code:
<com.wubydax.romcontrol.prefs.FilePreference
android:key=[COLOR="red"]"testfile"[/COLOR]
android:summaryOff="File doesn't exist"
android:summaryOn="File exists"
android:title="Test File Preference" />
The reason this is used by some devs, apparently, is when you need to mod smali file, which originates in a class that does not take context as parameter. Without context you cannot call the ContentResolver, so you cannot retrieve from the database. So what you can do instead is create a boolean condition based on existence or non existence of a certain file. File class does not require context. All it needs is to be instantiated as object and be given a string as path. For exampple:
Code:
[COLOR="Green"]File[/COLOR] [COLOR="Blue"]file[/COLOR] = new [COLOR="green"]File[/COLOR]("[COLOR="Purple"]/data/data/com.wubydax.romcontrol/testfile[/COLOR]");
means that object file of class File is a file located at /data/data/com.wubydax.romcontrol/ and called "testfile". In java class File you have a method (boolean) which is called "exists". So a condition can be made like this:
Code:
if(file.exists){
int i = 1;
} else {
i = 0;
}
So you can create a boolean method that will return 0 or 1 based on existence of the file at certain location.
This is the idea behind this preference.
The key for this preference is THE NAME OF THE FILE.
YOU DO NOT SPECIFY THE DEFAULT!!!
The preference looks like switch preference. But it acts differently. Youc an specify summaryOn and Off as you need. It does not write into database. It just creates and deletes the file.
Script executing PreferenceScreen:
As entioned above you can create PreferenceScreen which will execute shell scripts upon click. Example:
Code:
<PreferenceScreen
android:key=[COLOR="Red"]"script#test"[/COLOR]
android:summary="Click see what happens"
android:title="New Preference Screen" />
Note the key format. It has to begin with script#! The part after the hash (#) is the name of the script you wish to execute, in this case the script is test.sh which you can find in the source you pulled inside assets folder..
Where are the scripts??? You put them inside assets folder (see post #2). You name your scripts f.e. test.sh script (has to end with .sh). But you do not add the .sh extension to the string (we do that in code).
Every time your app launches it checks for scripts in the assets folder. It wants to make sure all the scripts ar being copied to our home dir. Inside files folder there we create a folder called scripts. All your scripts will be automatically copied there from assets, given permission 0755 and ready to be executed.
Wgen a user clicks on a Script Executing PreferenceScreen, the app looks if a script with that name exists in our files dir. If it does, it attemts to execute it. I have explained in post #2. We also check just in case that the script is executable. There is native java method to do that. So if you or your user just add a script to the scripts folder in home directory and forgot to make it 0755, we do that for you in java with this method:
Code:
if (script.exists()) {
[COLOR="Blue"][B]boolean isChmoded = script.canExecute() ? true : false;
if (!isChmoded) {
script.setExecutable(true);
}[/B][/COLOR]
Command command = new Command(0, pathToScript) {
@Override
public void commandCompleted(int id, int exitcode) {
super.commandCompleted(id, exitcode);
if (exitcode != 0) {
Toast.makeText(c, String.valueOf(exitcode), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(c, "Executed Successfully", Toast.LENGTH_SHORT).show();
}
}
};
try {
RootTools.getShell(true).add(command);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (RootDeniedException e) {
e.printStackTrace();
}
}
Make suer your scripts are of valid shell format, test them separately before you put them in the app. Be careful, all the scripts are being executed under sudo. Means anything you write shall be done. Do not make mistakes in your script. Adding su to your scripts is not necessary. We execute them as root anyway.
So...
Create a shell script and test it on your device
Place it inside the assets folder of your app
Call it f.e. killbill.sh
Create a PreferenceScreen entry and givie it a key android:key = "script#killbill"
Compile the app
Clicking on that preference should execute killbill.sh which will now be foind in /data/data/com.wibydax.romcontrol/files/scripts/killbill.sh and have permissions 0755.
DO NOT SET DEFAULT FOR PreferenceScreen EVER!!!
Intent opening Preference Screen:
Code:
<PreferenceScreen
android:key=[COLOR="Red"]"com.wubydax.gearreboot.RebootActivity"[/COLOR]
android:summary="Opens TWSwipe app to help you choose a different swipe activity"
android:title="Reset TWSwipe Action" />
This is a regular preference screen, so it would seem, but it has a special function. Usually, in order to open an intent with PreferenceScreen, you need to specify a whole lot of intent rules, like action, target class, target package and so on. We have made your life easy. If you want to link to an app from your rom control application, all you need to do is to specify the activity you wish to run as a key to this preference.
You are not allowed to use "." in any other preference key. If you use "." the app will read it as possible intent. If it cannot resolve it, it will make it disappear from the list.
This kind of preference is fully automated. Once the app reads the key, it does all the work for you, it sets the icon for the preference as the app icon, it creates a viable intent.
If the user doesn't have an app that you link to installed, the app will never appear in the preferences. So the user can never click on it. Because otherwise it would give FC to the app.
Nested PreferenceScreen:
If you include regular preference screen, you never need to set a key. Preference screen that envelops the items inside of it will always lead to a nested preference screen that has some included preferences. and so on. We have a loop running through your entire preference tree and detecting all your preference screen and differentiating them by their abilities (being script executing, being intents and so on).
Nested Preference Screen would look like this:
Code:
[COLOR="Red"]<PreferenceScreen
android:summary="New Preference screen"
android:title="New Preference Screen">[/COLOR] [COLOR="Green"]<-- Start of nested preference screen[/COLOR]
<PreferenceCategory android:title="new category" />
<CheckBoxPreference
android:key="text_checkbox"
android:title="Checkbox" />
<SwitchPreference
android:key="test_switch"
android:title="Switch" />
[COLOR="Red"]</PreferenceScreen>[/COLOR] [COLOR="Green"]<-- End of nested preference screen[/COLOR]
Inside of it you can have more preferences and more preference screens.
PreferenceCategory:
Preference category is an enveloping kinda preference. It is different in color and appearence then the rest. It makes sub-portions of preference screen look separate from each other and easier to identify. F.e.:
Code:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
[COLOR="Red"] <PreferenceCategory android:title="Status Bar Mods">[/COLOR] [COLOR="Green"]<-- start of preference category[/COLOR]
<SwitchPreference
android:defaultValue="true"
android:key="clock_visibility"
android:summaryOff="Clock is hidden"
android:summaryOn="Clock is visible"
android:title="Set Clock Visibility" />
<CheckBoxPreference
android:defaultValue="false"
android:key="brightness_visibility"
android:summaryOff="Brightness slider hidden"
android:summaryOn="Brightness slider is visible"
android:title="Notification Brightness Visibility" />
<com.wubydax.romcontrol.prefs.MyListPreference
android:defaultValue="2"
android:entries="@array/clock_position_entries"
android:entryValues="@array/clock_position_values"
android:key="any_clock_position"
android:title="Status Bar Clock Position" />
<com.wubydax.romcontrol.prefs.MyEditTextPreference
android:defaultValue="simpletext"
android:key="carrier_text"
android:title="Set Custom Carrier Text"
/>
<com.wubydax.romcontrol.prefs.ColorPickerPreference
alphaSlider="true"
android:defaultValue="-16777215"
android:key="clock_color"
android:title="Choose Clock Color" />
<PreferenceScreen
android:key="script#test"
android:summary="Click see what happens"
android:title="New Preference Screen" />
<com.wubydax.romcontrol.prefs.SeekBarPreference
min="0"
unitsRight="Kb/s"
android:defaultValue="10"
android:icon="@null"
android:key="network_traffic_autohide_threshold"
android:max="100"
android:title="Autohide Threshold" />
<PreferenceScreen
android:summary="New Preference screen"
android:title="New Preference Screen">
<PreferenceCategory android:title="new category" />
<CheckBoxPreference
android:key="text_checkbox"
android:title="Checkbox" />
<SwitchPreference
android:key="test_switch"
android:title="Switch" />
</PreferenceScreen>
<com.wubydax.romcontrol.prefs.IntentDialogPreference
includeSearch="true"
setSeparatorString="\##"
android:key="choosen_app_gear"
android:title="Choose App" />
<com.wubydax.romcontrol.prefs.FilePreference
android:key="testfile"
android:summaryOff="File doesn't exist"
android:summaryOn="File exists"
android:title="Test File Preference" />
[COLOR="red"]</PreferenceCategory>[/COLOR] [COLOR="Green"]<-- end of PreferenceCategory[/COLOR]
</PreferenceScreen>
This is it for now, more per demand and need. Have fun!​
General tips and tricks
Some tips and tricks
Running app and debugging:
Android studio provides you with built in logcat. Not only that you can debug the app you're working on, you can debug any app you're modding too. Just need to specify the filter for the logcat and the package name. Dig in and you will find some cool features.
You need to have unknown souces enabled and usb debugging enabled to run your compiled app directly on your device.
1. You can install and run this app as user app. It does not need to be system app. For now no features require it. You can of course include it as system app in your rom. We recommend pulling the base.apk from data folder and pushing to /system/priv-app
2. You do not need USB cable to debug and run your app from studio. There is anifty app I am using. You can download it here https://play.google.com/store/apps/details?id=com.ttxapps.wifiadb&hl=en. All you need to do is open the command line on your pc and type adb connect <ip number of your phone in the network>:5555. The app will provide you with an IP number.
Now studio will recognize your device as USB debugging device even though it's not connected with usb cable. I just hate cables.......
Including key specific functions:
For now all our work is done automatically for us. You click a preference and the work is done. But what if you have a key that you want to do alittle more with than just write into database? I will give you an example.
We have a SwitchPreference in our app that enables/disables call recording. That mod requires restart of InCallUI.apk. Now you can of course restart it by creating a Script Running PreferenceScreen item called Reboot InCallUI and it will be fine. That's what you have been doing so far. But let me show you what you can do now that you own your source code.
We have two ways to kill that app. Silently (without user knowing - very cool) or informing the user. Let me show you how it would be done.
Let's say you create a preference for call recording:
Code:
<[COLOR="red"]SwitchPreference[/COLOR]
android:defaultValue="true"
android:key="[COLOR="Red"]toggle_call_recording[/COLOR]"
android:summaryOff="Call recording is disabled"
android:summaryOn="Call recording is enabled"
android:title="Enable/Disable Call Recording" />
The two things we need to know is the key and the class instance of preference - which is SwitchPreference.
Let us go to the java class HandlePreferenceFragments and find a method called public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){}}. In android studio you can search through class by pressing ctrl+f.
In that method we have switch by the preference class name (INSTANCE). So we have this case:
Code:
case "SwitchPreference":
SwitchPreference s = (SwitchPreference) pf.findPreference(key);
s.setChecked(sharedPreferences.getBoolean(key, true));
break;
What this means is: if the preference is of kind SwitchPreference, when the preference is changes, do something..... So.... let us do something with our SPECIFIC switch preference for our SPPECIFIC key!!!
Let us try this:
The silent way:
Code:
case "SwitchPreference":
SwitchPreference s = (SwitchPreference) pf.findPreference(key);
s.setChecked(sharedPreferences.getBoolean(key, true));
[COLOR="Blue"][B]if (key.equals("toggle_call_recording")) {
Command c = new Command(0, "pkill com.android.incallui");
try {
RootTools.getShell(true).add(c);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (RootDeniedException e) {
e.printStackTrace();
}
}[/B][/COLOR]
break;
This will kill the InCallUI every time the user switches that switch. So what happened here? The user switched the switch, the boolean got written to the database (in a different method), then the app relevant to this key was restarted. Next time a user makes a call - the call recording will be updated!!!
Now let us do it in a no silent way:
Let us inform the user. We have a little method in that class called public void appRebootRequired(final String pckgName) { ...}. Let us try to use it...
So let us go back to our onSharedPreferencesChanged method and instaed of the condition we used silently, we do something like this:
Code:
case "SwitchPreference":
SwitchPreference s = (SwitchPreference) pf.findPreference(key);
s.setChecked(sharedPreferences.getBoolean(key, true));
[COLOR="blue"][B]if (key.equals("toggle_call_recording")) {
appRebootRequired("com.android.incallui");
}[/B][/COLOR]
break;
The user clicks on the preference and see what happens:
Now for InCallUI it might be better to restart the app silently. Since the change is not visible to user anyway. But if you need to restart systemui, then it might be better to inform the user. So all you need to do is instead of passing a string "com.android.incallui" pass a string "com.android systemui". The method will do everything automatically. See how the dialog changes:
Adding more than one special key
If you need to add more than one special key (see popst #3 for instructions and explanations), you have 2 options:
1. We can go on with the if/else conditions, like so:
Code:
case "SwitchPreference":
SwitchPreference s = (SwitchPreference) pf.findPreference(key);
s.setChecked(sharedPreferences.getBoolean(key, true));
[COLOR="blue"][B] if (key.equals("toggle_call_recording")) {
appRebootRequired("com.android.incallui");
} else if (key.equals("some_other_key")) {
//do something you want
} else if (key.equals("again_some_key")) {
//do something different
}[/B][/COLOR]
break;
2. Or we make a switch for that based on key. Like so:
Code:
case "SwitchPreference":
SwitchPreference s = (SwitchPreference) pf.findPreference(key);
s.setChecked(sharedPreferences.getBoolean(key, true));
[COLOR="Blue"][B]switch (key){
case("toggle_call_recording"):
appRebootRequired("com.android.incallui");
break;
case("toggle_clock_visibility"):
appRebootRequired("com.android.systemui");
break;
case("some_other_key"):
//do something
break;
case("some_other_different_key"):
//do something different
break;
}[/B][/COLOR]
break;
Please note:
You can add the specific conditions to any preferences
You need to add them to the same preference instance as the preference that the key belongs to. Right now I showed how to do it for switch preference. You can do the same for any preference. If the key belongs to checkbox preference, you need to put the conditions inside the case of the "CheckBoxPreference" and so on
You need to make sure your condition comes AFTER our built in lines. Like in this case I added it after the initiation of the object and setChecked
You need to finish your conditions BEFORE the main break; of the case.
More to come at later time and per demand...
Huge THANK YOU @daxgirl & @Wuby986 for this!! Folks will love this app!!
Awesome!! Glad to see you have finally released it. I'm sure it'll be fantastic!!
HIZZAH!!! Kudos to wuby and daxgirl!!!
And just when I thought I could take a break from Android.....
The Sickness said:
And just when I thought I could take a break from Android.....
Click to expand...
Click to collapse
You??? Duh.......
Sent from my awesome g920f powered by 6thGear
Thebear j koss said:
View attachment 3384150
HIZZAH!!! Kudos to wuby and daxgirl!!!
Click to expand...
Click to collapse
Mostly to daxgirl
She will say no, but is true
The Sickness said:
And just when I thought I could take a break from Android.....
Click to expand...
Click to collapse
Eheehhehe there is always a good reason to start again
Delivered as promised, great work you 2, thanks a million bunch to you both & to your great testers.
PS : @daxgirl @Wuby986 any chance this app will have the phone make us coffee in the morning ! ( kidding, Sorry )
@daxgirl and @Wuby986 you guys really rock? thanks, thanks and thanks! ?
claude96 said:
Delivered as promised, great work you 2, thanks a million bunch to you both & to your great testers.
PS : @daxgirl @Wuby986 any chance this app will have the phone make us coffee in the morning ! ( kidding, Sorry )
Click to expand...
Click to collapse
Over the past couple weeks @tdunham and @ rompnit definitely tried to make us do that. .. the answer is... of you can make your coffee machine get context and use content resolver, we will deliver the toggle to trigger your morning pleasure
Sent from my awesome g920f powered by 6thGear
daxgirl said:
Over the past couple weeks @tdunham and @ rompnit definitely tried to make us do that. .. the answer is... of you can make your coffee machine get context and use content resolver, we will deliver the toggle to trigger your morning pleasure
Sent from my awesome g920f powered by 6thGear
Click to expand...
Click to collapse
@daxgirl I'm sure if anyone can !, you can, but unfortunately my coffee machine doesn't speak android at all:crying:, anyway thanks a million bunch for all your great work & help & all ( best of luck with the new upcoming rom btw:good: )
claude96 said:
@daxgirl I'm sure if anyone can !, you can, but unfortunately my coffee machine doesn't speak android at all:crying:, anyway thanks a million bunch for all your great work & help & all ( best of luck with the new upcoming rom btw:good: )
Click to expand...
Click to collapse
Thanks! We really appreciate!
As for the rom. .. it will be awhile I guess...
In a mean while I will get back to writing instructions.
Some screenies added to the op...
Sent from my awesome g920f powered by 6thGear
daxgirl said:
Thanks! We really appreciate!
As for the rom. .. it will be awhile I guess...
In a mean while I will get back to writing instructions.
Some screenies added to the op...
Sent from my awesome g920f powered by 6thGear
Click to expand...
Click to collapse
You're most welcome, and thank you of course ( pics ( app ) looks great btw )
PS : about your rom, a word to the wise ( if I may ! ), just make it bug free as much as possible ( witch is no problem for you I'm sure ), don't throw everything in it at 1st ( users will always want more and new stuff of course, normal ! ), again thanks a million and best of luck, keep up the great work.
Amazing! Now I need to fold up my sleeves and start learning something.
Sent from my SM-N9005 using Tapatalk
claude96 said:
You're most welcome, and thank you of course ( pics ( app ) looks great btw )
PS : about your rom, a word to the wise ( if I may ! ), just make it bug free as much as possible ( witch is no problem for you I'm sure ), don't throw everything in it at 1st ( users will always want more and new stuff of course, normal ! ), again thanks a million and best of luck, keep up the great work.
Click to expand...
Click to collapse
This is a wonderful idea and this is exactly our intention always. We are not for being the best or the fastest or the most unique. We are all that in our hearts It's just we are too jumpy from thing to thing... and we never manage to finish a rom between all our ideas... I am starting to think we might not have been meant to
kmokhtar79 said:
Amazing! Now I need to fold up my sleeves and start learning something.
Sent from my SM-N9005 using Tapatalk
Click to expand...
Click to collapse
My dear friend, if anyone can, YOU CAN!!! I have every faith in you!!!
Second post with instructions now contains an explanation of basic idea and how the app works... The rest after I wake up. It's almost 5am here and I am semi conscious... See ya guys tomorrow!
great, good job as always, i was thinking about one thing: when we add a new mod we learned to put our "key" in settings system database, so my idea is:there is a way to make a general observer that read all the "key" in system database so as to update our choices in real time?

[SOURCE CODE][DEV TOOL][SDK 21+]6thGear RomControl v2.+ for Devs

6htGear Rom control V2.1
By @Wuby986 & Daxgirl
Hello everyone!
So here we go again... V2.0
Big thanks:
We would like to begin from crediting people, who gave us ideas, inspiration and, most importantly, their free time, in order to make v2.0 a reality.
To our dearest friends and talented developers, @tdunham and @DaOldMan:
Guys, you OWN this. You made this happen. You pushed us and we pushed you, and together, you, us and rom control, have grown to be what we are today.
No thanks can ever be enough for long nights of applying patches, merging sources, connecting through teamviewer and working out kinks together. @Wuby986 and I are forever in your debt.
Why different thread?
1. The entire application is different. It barely qualifies as an update anymore.
2. All the preferences are different. The way they work is different. It requires new way of doing things. Radically new.
3. new support library and new basic structure.
4. To sum it up... it's too different to maintain same thread for both versions
Project characteristics:
1. Rom control is an open source project, designed to provide rom builders with a core code for compiling android application for controlling core functions of their roms and mods through Content Provider of Settings.System sqlite table
2. Rom control is designed with consideration of the fact that most rom builders do not have sufficient skills in original android development to build application with this functionality on their own
3. The emphasis is given in this version (even more than previous one) to outsource most conditions and attributes to xml, and so to minimize the need of the user (rom builder) to be subjected to java programming
4. In addition to familiar utilization of ContentResolver to pass data between RomControl and system, the project offers additional properties, such as file based preference, URI selection preference, Direct intent to shortcut app preference, preference listing image thumbnails for previews, script running preference, automated template for "About Us" section, automated dialog for changelog, backup and restore finctionality and more.
5. The project is designed to be compiled in Android Studio using the latest sdk tools and gradle tools.
6. The project essentially is designed to be a system application with privileged access, and therefore needs to be installed in /system/priv-app to be granted some of its permissions
7. The project requires root access for some of its functionality. Mainly running shell scripts with su and killing some app processes.
License and sharing policy:
1. This project is distributed under GNU General Public License as open source code. The copy of said license can be obtained and reviewed here
2. As such, this project is protected from claiming exclusivity by anyone.
3. Any developer wishing to use this code, with accordance to the license, must provide full source code for each updated version. That means, for any new version of the rom including updated RomControl application, a link to full source code of the latest version must be provided.
4. By modifying and using this code, you automatically accept the License conditions and must be compliant with GPL, as stated below:
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
Click to expand...
Click to collapse
5. You're under no obligation to thank us, credit us or tag us in your official postings while distributing your copy.
6. You ARE, however, prohibited from removing our copyright information from our source code.
7. You are obligated to keep the code open under GPL. Failure to provide sources for updated copies of your work will result in complaint first to XDA officials for license infringement and further to GPL legal department.
8. Using the source code on any other forum outside of xda is of course allowed with accordance to the license and sharing policy, provided the sources are kept open and obtainable by anyone.
9. Using apktool to compile a copy of this code after making changes in the decompiled form of someone else's application is strictly prohibited, as the developer will not be able to provide full open source of their version. Any illegal use of any copy of this project can be and should be legally stopped by the owner of the code copy.
10. This voids rule number 12 of xda promising a developer exclusivity over their product. This product is yours, but the code belongs to the public. You are NOT TO HOLD COPY OF ROM CONTROL EXCLUSIVE.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Click to expand...
Click to collapse
Open source libraries included in this project:
1. RootTools by Stericson
2. Sergey Margaritov's ColorPickerPreference modified to adopt to our needs
3. CircleImageView by hdodenhof
Project requirements:
1. Installed and updated android sdk, including but not limited to:
Android SDK Build-Tools 24
Android SDK Platform-Tools 24
Android support repository 33
Google repository, rev 29
Latest android support library
2. Android studio version AT LEAST the latest stable version (currently 2.1.2), you can use the canary channel as well, currently on 2.2.0 preview 5.
3. Updated gradle tools
4. Working knowledge of importing project into Android Studio and troubleshooting gradle sync. If you don't know how to, Google it.
5. EXTENSIVE knowledge in android modding:
This project is for rom developers and modders. It helps coordinate between your users and your mods. If you don't build roms or don't have mods, this project means nothing to you.​
What support you can expect to get:
1. Code explanation regarding major functionality
2. Adding new preferences and navigation items
What support you CANNOT expect:
1. Setting up android studio
2. Debugging gradle issues and compiling
3. Changing colors, strings, adding themes, design, changing setup... - Android documentation is vast and Stackoverflow is even vaster.
4. Smali modding
5. Private messaging support - DO NOT EVEN TRY
6. Asking for compiled apk file.
This is NOT an application thread. This is NOT an application. This is a SOURCE CODE for MAKING application.
The answer to a question "Can someone give me a compiled version" is "And what are you going to do with it?"​
Project main Git repository:
Here
Thread list of contents:
Starting the project
Adding navigation drawer items
Running android app: where, how, builds, gradle tasks and you-name-it
Preferences - Part 1: Introduction
Preferences - Part 2: Types of preferences
Themes, About Us activity and Changelog dialog
Backup and Restore
XDA:DevDB Information
6thGear RomControl v2.0, Tool/Utility for all devices (see above for details)
Contributors
daxgirl, wuby986, tdunham, DaOldMan
Version Information
Status: Testing
Current Stable Version: 2.1
Stable Release Date: 2016-08-26
Created 2016-07-06
Last Updated 2016-08-26
Latest Update details:
Post number 195
Step 1 - Importing the project:
1. Perform full installation of the latest stable version of Android Studio in your environment. You can find info about stable and canary releases here
2. You can have more than one version of android studio installed on single platform. For more information please read further on the same page in section Using Multiple Android Studio Versions. I personally do recommend the latest canary build, which is currently AndroidStudio 2.2.0 preview 5. But you can always go with the stable release. Or beta channel.
3. Make sure your sdk is updated, including sdk for platform 24 (nougat). The compile sdk for this project is 24.
4. Make sure your support repositories are configured and updated.
5. Click on our github repository link on the OP first post and make sure you're connected with your github account. If you don't have one - create it! Why? because you will need to share your sources for this project. And because you all use as mantra that you can mod android apps because it's open source. So BE OPEN SOURCE. Have your name on github.
6. Once you're logged in into github, fork our repository. In the right upper corner of our main git repository you have those buttons:
Click "fork" to make a copy of this repository in your own repositories. Now you have your own repository.
7. On YOUR repository find this green button on the top right above the code, which says "Clone and Download". DO NOT DOWNLOAD ZIP. Instead, click the little "clipboard" icon to copy the .git uri and return to studio.
8. In studio: File > New >Project from Version Control > Git
9. Paste the git uri and choose destination. Click ok. Android studio will import the project from git and open it for you.
10. At this point if you're asked to update gradle build tools or anything else, do it. Wait for gradle to sync with project files. If you get errors, resolve them as referenced. If you cannot, google is your friend.
We WILL provide some support for initial importing of the project and setting it up for a very limited period of time. Gradle can be a tricky business. Please be sure to provide us with specific error from gradle log and a line in the gradle script on which the error is made.
11. We WILL know if your errors are because you didn't update sdk and build tools. And we will kick your butts for posting without following instructions. Remember, our time is valuable and given to you for free. Our instructions are clear and we made a huge effort to write them. If you can't be bothered with following them, beware.
12. Once the gradle is done syncing without errors, just in case, click Build > Rebuild Project. Once that is done without errors and it says BUILD SUCCESSFUL, you can start building your project following the instructions on the next post.
Adding items to the Navigation Drawer:
1. Switch to project view.
It will be easier for you to navigate through project files. For that:
On the left panel on top, below the android studio menu, find this:
This is what your project will look right after you import it. This is module view. By default it is categorized and to work with it you need some understanding of this view.
Click the 2 arrow icon which is circled in blue and select "project"
Your structure will now change.
Navigate into the project by the following path: Project name > app > src > main
Now you will see directories, like: java, res, assets... and so on.
This is your working directory. You will be making your code changes here.​
2. Find a file called nav_drawer_arrays.xml. It is located in res/values folder. Double click on it to open.
You will see the following 3 arrays inside. The first one is a reference array (simple typed array) and the other 2 are strings arrays.
Those are WORKING ARRAYS. When you run the app as it is now, you will see all the items created in the navigation drawer based on this info.
Please read the comments we wrote in the xml file for you:​
Code:
<resources>
[COLOR="Green"][B][I]<!--The following array is for icons you want to use for your items
You can create new icons bu right clicking the drawable folder and choosing
New vector drawable
You have a great selection of items in xml vector format.
Those are supported starting lollipop.
YOU SHOULD NOT USE PNG. not even material one. Vectors will work best with any device density.
Once you have created the vector, reference it as regular drawable in the array below.
MAKE SURE THE ITEMS IN ALL 3 ARRAYS CORRESPOND IN ORDER AND ALL 3 ARRAYS ARE SAME LENGTH-->[/I][/B][/COLOR]
<array name="nav_menu_prefs_drawables">
<item>@drawable/ic_system_ui</item>
<item>@drawable/ic_phone</item>
<item>@drawable/ic_framework</item>
<item>@drawable/ic_notification_panel</item>
</array>
[COLOR="green"][B][I]<!--This array is for your items titles.
Use @string reference, so later on your app can be translated with ease
KEEP THE ORDER BETWEEN ALL YOUR ARRAYS-->[/I][/B][/COLOR]
<string-array name="nav_menu_prefs_titles">
<item>@string/systemui_prefs</item>
<item>@string/phone_prefs</item>
<item>@string/framework_prefs</item>
<item>@string/notification_panel_prefs</item>
</string-array>
[COLOR="green"][B][I] <!--This array is the most valuable one
Here you put the file names of the preference files you create in your xml directory
THEY MUST BE PRECISE AND CASE SENSITIVE!!! DO NOT ADD .xml SUFFIX-->[/I][/B][/COLOR]
<string-array name="nav_menu_xml_file_names" translatable="false">
<item>ui_prefs</item>
<item>phone_prefs</item>
<item>framework_prefs</item>
<item>notification_panel_prefs</item>
</string-array>
</resources>
3. Let's say you have 10 preference files in directory called xml. That means you will want to have 10 items referring to your preference files in the navigation drawer. That means you will need to have 10 items in EACH array. Create 10 empty preference files. DO NOT COPY THE ONES FROM RC v1.0. Just right click the xml folder, choose "New" and choose "New XML resource file". Give it a name and click ok. Leave them empty for now. create all the icons you need for them in the navigation drawer.
4. Populate the arrays with titles, icons and xml names. You're done. You now have a working items in the navigation drawer. You do not need any changes in java files. the items are being generated on run time and their onClicks redirected accordingly. If you run the app right now you should have 10 empty preference files.
We strongly encourage you to keep the ui_prefs.xml file and references to it in your project while you're working on it. It contains most valuable information about the kinds of preferences we have included and their various usages. You can remove it from arrays before making the release version. You can have it as last item in your arrays and use it as test dummy to see how things should work properly
Run!
Installing and running your builds in Android Studio:
First of all - data or system app?
The simple answer is SYSTEM. And not just system - we need some high level permissions, so definitely /system/priv-app. Why?
So for that we dig deeper into android permission system.
1. Writing settings into settings storage database:
This permission was revoked from data apps on Marshmallow. Meaning, THEORETICALLY, that only system apps can write into Settings.System. So how come we can write when the app is installed as data app? Oh, this is where THEORETICALLY part comes in. Permission to write system settings is declaired in framework in such a way, that it allows data apps to write there if they target sdk lower than 23 in their build. That permission level is called "pre23". That is why in our gradle we have a somewhat peculiar sdk division for building. Let's look at the image:
As you can see, target sdk is set to 22. This is not by mistake. This is by design so if you want to test the basic functionality of the app by installing debug version in data, it will not crash every time you flip a switch.
This is the definition of pre23, we target sdk 22 so the pre MM permissions can be achieved by running the app in data.
Although all of you will be including this app in your roms in system priv-app, you will be working with it quite alot as you build it. We want you to be able to run it from data if you wish so. if we target sdk 23 and up it will never run from data, unless installed also in system.
You are free to change this to 23 or 24. But NEVER run it while installed only in data then. It will crash like a drunken monkey.
Also, changing it to 23 or 24 for TARGET sdk is meaningless. It's not better because it's a higher number. For target sdk it makes no difference.​
2. Running reboot
We run reboot functions in a proper android shutdown sequence. Any of you that are familiar enough with linux kernel based platforms KNOW the system should not be shut down by killing it's process.
Therefore all reboot functionality in our app is native android reboot. For THAT we absolutely need the app to have an initial copy in priv-app. If the app is only installed in data, clicking on any reboot option, either from reboot menu or from reboot dialogs, will result in FC in your face. the following permissions cannot be obtained by data apps NEVER EVER.
Code:
<uses-permission android:name="android.permission.REBOOT"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.DEVICE_POWER"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.RECOVERY"/>
3. But we have root permissions? Isn't it enough?
So here is the thing you should remember:
Android doesn't give a damn about root permissions. When we run command under su we talk to the linux kernel through shell. We do not run it on android level. Android is NOT linux. There is NO android permission which is compiant with su.​When we are talking about android application permissions, we are talking about PackageManager, which is android framework system service, that grants the permissions to perform certain action. Package manager does not know su. It is not part of linux platform. It is android. Android is not designed to have root access. Not on any level. it does not recognize unix commands by default.
So when we execute your scripts, android doesn't do it. Our application code doesn't do it. We just pass it to the kernel as runtime command. Remember that, when you come complaining that your scripts don't run. We can't help it. If the kernel refuses to execute them, something is WRONG in the script syntax or structure.​
4. So data or system? The answer is - when you build and test run your app - BOTH
Can you run apps from android studio while one of the copies is installed in system? Absolutely. As any system app, app is allowed to have an update.
The most important thing is for that update to have same signature and same package as the app in system. Once the app is installed in priv-app it has privileged permissions. You can after that, as oyu build, install updates in data, so you don't have to push every single test build into system and reboot, and all privileged permissions will work.​​
Gradle, baby!
Gradle is a build tool. You can read on history of gradle online. It was not developed with any relation with android. Google decided to adopt gradle as their primary build tool for their primary development environment for android and hence, android gradle plugin was born.
Build tool is a way to "put things together in orderly fashion". In essence, android application is a bunch of files in folders. Making it into a running product is a matter of some complexity. Connecting java to resources, signing, packaging, updating manifest, setting primary configs and build related configs, compiling java, compiling dependencies, including multiple modules, being able to have several builds and flavors in one project - this is what gradle does for us.
If you wish to learn more about gradle for android, please watch this amazing video https://www.youtube.com/watch?v=jJ9j7MvGPkU.
Gradle, in a manner of speaking, is a bunch of tasks. Tasks are executed in specific order. Files are being copied, deleted, compiled and packaged as result of single button click.
Android gradle plugin comes with specific predifined tasks. We can also write our own tasks, which we usually do, for our own usage. We will talk about OUR specific tasks later on in the advanced section.
For now we will talk about basic android gradle tasks, such as assembleRelease, assembleDebug, installRelease, installDebug and so on.
1. Clicking RUN button
If you have a look on the top panel of android studio you have this green "play" button next to a selection box which, usually, says "app". Like this:
This is what will appear on the run menu when you first open the project and it's done syncing with gradle. If the "app" selection box has a red "X" on it, means gradle is syncing now or has failed to sync and you need to find out WHY and fix it. Once there is no red "x" current configuration is ready to run.
When you click the green run button, it will run whatever task is in the selection box. When it says "app" in the selection box and you click run, it will do the following:
1. Compile debug build
2. Install it on your connected device
3. Run it​
So what is "app"? App is the main of the module we want to run. It is the only module in our project. So by running "app", we run the RomControl application on a device in DEBUG mode.
Why is it good to run in debug mode? For 2 reasons:
1. Run "app" configuration supports instant run. You can read more on instant run here. This will push the code changes into your running app on device and apply immediately. It's very handy if you add a preference or 2 and want to test how it looks or works. If instant run is impossible for your current build tools, android studio will tell you and it will tell you why. It usually means that you need to upgrade android gradle plugin. This can be done with ease.
2. Running app module in debug mode will give you full stack trace if there is an error. It will be easier for you to copy the log here for us to have a look at and debug. Or debug yourselves.​
The downside of running debug mode?
1. It's somewhat slow. Meaning the app on the device is a little slow in debug mode (although now it's not as slow as it used to be)
2. Debug mode by definition runs from data. So none of the reboot options will work. So if you want to test actual changes that require reboot from our app, you need to have a system priv-app version installed. You can have a debug version installed in priv-app and then you can use instant run, like we spoke before.​
2. So how do we make a release version?
1. Generating signing key
For that we need a signing key. We already made a full prepared platform for you to run release build in our app gradle build file. All you need to do is create a signature and make some little edits. So, let's roll.
To create a signature please follow these instructions
Please remember or write down the following:
1. Path where you create the signature
2. Key password
3. Store password
4. Key alias​You do not need to generate the release build just yet. Just finish creating your own keystore and remember where you put it.
Now go to the parent folder where your rom control project sits. For example if you put it in AndroidStudioProjects folder, in the same folder create a folder called "keys" (no caps, just "keys"). Copy your keystore there. Or originally create it there.
Now go back to android studio. to the left project panel (provided it is in project view, like we asked you to make it) and scroll down... You will see at the very bottom some singleton files, like gradlew, gradlew.bat, gradle.properties and so on. One of the files there is called key.properties. Double click on it to open.
Inside you will see 4 strings. Like this:
Out in your actual key information. The one you used to create your key. you need to make changes to all 4 fields.
for example:
As you can see we used relative path to the keystore. Which is why it's supposed to be in the parent folder of your folder containing your project in direcroty called "keys".​
2. Telling gradle to use our signing key for release builds
On the left project panel look inside the "app" module folder. On the bottom of it, after the AndroidManifest.xml file, you will see a builg.gradle file. Double click to open it.
This is a gradle file for building our app module. You will see there are alot of configurations related to android build there. It will look something like this:
You need to un-comment the sections pointed to with red arrows. To comment or un-comment the section in android studio, select the section and click "ctrl + /"
Now you should be ready to build the release version. Let's test that:
1. On the right upper corner of the studio window you will see little vertical "gradle" tab. Like this
Click on it. A side window till open with gradle tasks. Like this:
2. Open app > tasks > build
3. Find a task called assembleRelease and double click on it.
4. Wait for it to finish. You will see tons of things running in the gradle console window on the bottom. Provided you didn't mess up any of the previous steps, it will work fine.
5. Once it's done, check that you did now have errors and that build was successfull.
6. If all is good, open in file manager your project folder > app > build > outputs > apk. There you should see your freshly compiled release version. Release version is called simply RomControl.apk. it is already zipaligned and signed. You can go ahead and use it in your rom, push it into priv-app and test. So on.
3. So every time I need to run assembleRelease and push the apk into priv-app and reboot? NO!!!
1. Once you run your first assembleRelease, take that apk and push it into system priv-app. Reboot your device.
2. Now look again into the app > tasks in the gradle window on the right. You also have there "install" tasks. Open it and find "installRelease". Connect your device with app installed already in priv-app and double click on installRelease. This will install the release as UPDATE in the DATA apps. This is so you don't need to push the app to device as you're building and testing. You can make code changes, install release as data and run it FULLY. Becasue you have the original sitting in the system, it will have all the premissions for the reboots. So you can build and test from data.
3. Please remember that as you build and test only the data version of your app is updated. So once you are done testing and the build is final, run assembleRelease and take the final apk from the outpute/apk folder to include in your rom.​
4. Do I need to go to the gradle menu on the right all the time to run installRelease? NO!!!
After you run a task from the gradle menu have a look at the run button on the top panel. Surprise! It doesn't have "app" selected anymore. it has the latest task you ran!!! Look:
Now if you click the "run" button it will run the selected task. If you want to select another task from the tasks you used in the past, Just select from the selection box menu and click run.​
So which build to run and when?
1. If you're building and testing continuously, we recommend keeping the app as debug in data only and NOT TO USE the reboot options.
For adding preferences and building your ui you don't need to use reboot options. Just click LATER on reboot dialogs if you include reboot options.
So you can use instant run, switch to "app" configuration and keep running in debug mode from data as you build.​2. When you go further into preference testing, we recommend uninstaling the debug version. creating signed release version and push into priv-app. From this point on run installRelease task to instal release update in data as you build and correct and test scripts and reboot options.
3. When ready to go final release with your rom, use task assembleRelease to build your final version and include it in your rom zip
4. Commit latest changes to your github repository​
Uploading sources to git
1. Provided you followed our instructions and forked the project source code and then cloned it to studio, it is now connected to your forked git project.
2. Any new file you add will ask if you want to add it to git. And will turn it's color to green if added. Any file that is not added will have brown color.
3. To add brown colored file to github, right click it, choose git > add
4. You should have the following available on the top panel:
The green arrow is for commiting and pushing changes to github. Once you push it the following window will open:
5. Check what files you would like to commit. For example, never commit key.properties file which contains your key password.
6. Write description of your commit and choose from the blue button selector box commit and push.
7. Make a habit of committing your work daily or at least on a new feature basis. It easier to follow for you and also serves as backup.​
We would be happy to talk more about gradle and various tasks, but this post had a specific purpose. To teach you how to manipulate build types and use it to you advantage. Please ask us specific questions about gradle tasks related to your build.
Preferences - Part 1: Introduction
1. Major change in implementation:
1. For this release we made a major change in how preferences are handled. They are not handled anymore. They handle themselves.
2. For that to happen we needed to subclass ALL native android preferences except PreferenceScreen and PreferenceCategory.
3. What does it mean to subclass? That means we created java classses which extend (resemble) native android preferences and we wrote our own implementation of how they should behave, how they should load their values and write their values.
4. That being said - there is no more standard android preferences in this project. No more SwitchPreference, no more CheckboxPreference, no ListPreference... None of those.
5. Two reasons for that:
1. We didn't want you to get lost in special conditions anymore. We wanted you to be able to set if the preference should restart systemui from xml file when you declare preference. For that we needed to add custom xml attributes. For that we needed a preference class to be able to acknowledge that. So we needed a custom preference class.
2. We wanted the preference to manage itself in by reading and writing from and to database. Instead of fragment running endless iterations and conditions. When our new preferences are born (attached to the screen), they get their value from the database directly. No one needs to set values to them. When they are changed, they know to write into database directly. From their own class. Not containing fragment doing that for them.​
2. Types of preferences
1. Two state preferences:
MySwitchPreference
MyCheckboxPreference
FilePreference​
2. Dialog preferences:
MyListPreference
MyEditTextPreference
IntentDialogPreference
ThumbnailListPreference
ColorPickerPreference​
3. Native preferences(PreferenceGroup subclasses):
PreferenceScreen
PreferenceCategory​
4. Slider Preference:
MySeekBarPreference​
5. Special preferences:
OpenAppPreference
UriSelectionPreference
RunScriptPreference
ImageHeaderPreference​
3. Setting defaults:
It is ABSOLUTELY VITALLY IMPORTANT that you set android:defaultValue to all the preferences that change and read values. That means:
MySwitchPreference
MyCheckboxPreference
FilePreference
MyListPreference
MyEditTextPreference
ThumbnailListPreference
ColorPickerPreference
MySeekBarPreference​
4. What happens if we use regular android preferences? Like SwitchPreference or ListPreference?
Nothing! Absolutely nothing will happen nor to this project, nor to your database and, MOST IMPORTANTLY, nor to your mods.
It will act like normal preference. It will not write to database. Your mods will not be affected and WILL NOT WORK.​
5. Custom attributes for value changing preferences and RunScriptPreference
1. app: packageNameToKill
This attribute is of type string and you will need to provide which app you want to restart when this preference changes value.​2. app:isSilent
This is a boolean type attribute, which is by default set to true. That means that if you don't set this attribute and you DO set the package name to kill, it will restart the app you want without warning as soon as the value has been changed. If it is set to "false", upon value change a dialog will appear with app icon and test informing user that for this action to take effect an app restart is required. They can then choose to kill app now or cancel the dialog and kill it later.​3. app:rebootRequired
This is also a boolean type of preference which by default is set to false. If you set it to "true", upon preference value change a dialog will appear, informing the user that reboot is required for this action to take effect. good example for that is changing the default app intent to open on home button double click. That needs framework reload.
If rebootRequired is set to true and you ALSO set package name to kill, reboot takes preference. Package to kill will be ignored.​
Preferences - Part 2: Types of Preferences
1. Two state preferences (meaning - can be true or false)
MySwitchPreference & MyCheckboxPreference
Code:
[COLOR="Teal"][B] <!--Following category shows variety of two state preferences-->[/B][/COLOR]
<PreferenceCategory
android:title="Two stated preferences test category">
[COLOR="DarkGreen"][B] <!--Normal Switch preference-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MySwitchPreference
android:defaultValue="true"
android:key="normal_test_switch"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Normal test switch"/>
<!--Switch preference which will throw a dialog that app reboot is required-->
<com.wubydax.romcontrol.v2.prefs.MySwitchPreference
android:defaultValue="true"
android:key="kill_app_with_dialog_test_switch"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Kill app with dialog switch"
app:isSilent="false"
app:packageNameToKill="com.android.systemui"/>
[COLOR="darkgreen"][B] <!--Switch preference which will in ADDITION to actual work, also silently restart app with given package-->
<!--Note, that isSilent attribute is by default TRUE. So you don't need to specify it if you want silent app restart-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MySwitchPreference
android:defaultValue="true"
android:key="kill_app_silently_test_switch"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Kill app silently test switch"
app:packageNameToKill="com.android.contacts"/>
[COLOR="darkgreen"][B] <!--Switch preference which will throw a dialog that following it's action device reboot is required-->
<!--Please note, even if you specify the need to kill app, once the rebootDevice attribute is TRUE, kill app attributes are ignored-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MySwitchPreference
android:defaultValue="true"
android:key="reboot_required_test_switch"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Switch reminding of need to reboot"
app:rebootDevice="true"/>
[COLOR="darkgreen"][B]<!--We can use kill app on checkboxes as well. Same goes for rebootDevice-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MyCheckBoxPreference
android:defaultValue="true"
android:key="test_checkbox_with_kill_app"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Kill app checkbox"
app:isSilent="false"
app:packageNameToKill="com.android.systemui"/>
</PreferenceCategory>
FilePreference
Code:
<PreferenceCategory
android:title="File preferences">
[COLOR="darkgreen"][B]<!--File preference is a very special kind of preference, which works like switch but has different output.
Normal switch preference, like any two state preference, write boolean true/false into preferences.
In our app it also writes 1/0 into database.
File preference doesn't write into database. If it is switched on, it creates a file in our app directory in data.
That name of that file is what you set as key.
This is widely used by [user=1042140]@tdunham[/user] for global boolean needs in systemui.
Please refer to his guide about setting global boolean to see appropriate smali application for this preference.
This is most useful for mods in smali files where you do not have context access to get content resolver.
Because File class is native java class and checking for it's existence does not require android context.
File preferences can have attribute to kill app or reboot device.-->[/B][/COLOR]
[COLOR="darkgreen"][B] <!--This is a simple file preference. Note that once it's switched on, a file with the name identical to key is created in
/data/data/com.wubydax.romcontro.v2l/files
When it's switched off the file is deleted.-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.FilePreference
android:key="new_file"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="New file preference"/>
[COLOR="darkgreen"][B] <!--This file preferences upon change will prompt to kill app-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.FilePreference
android:key="another_file"
android:summaryOff="Disabled"
android:summaryOn="Enabled"
android:title="Kill app file preference"
app:isSilent="false"
app:packageNameToKill="com.android.systemui"/>
</PreferenceCategory>
2. Dialog preferences
ColorPickerPreferece
Custom attributes:
alphaSlider, hexValue - both booleans, TRUE by default
Code:
[COLOR="Teal"]<!--The following category demonstrates various ways of using ColorPickerPreference-->[/COLOR]
<PreferenceCategory
android:title="Color pickers test category">
[COLOR="DarkGreen"][B]<!--Normal color picker preference-->
<!--Please note, the [COLOR="Red"][U]hexValue and the alpha are there by default now[/U][/COLOR]. If you want to cancel them, you need to specify false-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ColorPickerPreference
android:defaultValue="#ffccdd"
android:key="test_color_preference"
android:title="Normal test color picker"/>
[COLOR="DarkGreen"][B]<!--Color picker preference without the alpha slider and without the hex value
You can set false to both or one of them-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ColorPickerPreference
alphaSlider="false"
hexValue="false"
android:defaultValue="#ffffff"
android:key="no_alpha_color_key"
android:title="Color picker with no alpha or hex"/>
[COLOR="darkgreen"][B]<!--Color picker preference with kill app option
Note, [U]you can also use rebootDevice attribute[/U], like with two stated preferences-->[/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ColorPickerPreference
android:key="app_kill_color_key"
android:title="Color picker with app kill"
app:isSilent="false"
app:packageNameToKill="com.android.systemui"/>
</PreferenceCategory>
MyListPreference
Custom attributes:
app:dependentValue - will enable you to set dependencies upon choosing selected value. If a dependent value is selected by user, the dependent preference will become disabled.
Code:
[COLOR="DarkGreen"][I]<!--Example of simple list preference with radio button items
You absolutely HAVE to set dafaultValue and it has to be one of your entryValues string arrays
You can use any of the following with kill app attributes or rebootDevice attribute
Note, that you can now use dependency on list preference.
Custom attribute app:dependentValue will allow you to decide which list item, if selected,
will set dependent preferences disabled.-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MyListPreference
android:defaultValue="20"
android:entries="@array/test_list_entries"
android:entryValues="@array/test_list_values"
android:key="test_list_key"
app:dependentValue="1"
android:title="Choose items from the list preference"/>
ThumbnailListPreference
Custom attributes:
app:dependentValue - will enable you to set dependencies upon choosing selected value. If a dependent value is selected by user, the dependent preference will become disabled.
app:drawableArray - references array which provides resources for the thumbnail images for each list item
app:entryList - references array of strings to provide names for actual list items
app:entryValuesList - references array of strings for the entry values to be written to preferences and database for selected list item
Code:
[COLOR="darkgreen"][I] <!--Thumbnail list preference is a special kind of preference which allows you to show preview of the selected image
This can be useful f.e. for setting custom bg to toggles in systemui
Needless to say you need to put the same images you put in systemui in Rom Control in drawables
And you need to create 3 kinds of arrays in arrays.xml file. 2 string arrays for entryList and entryValuesList and one simple array
for drawable references. You can see the arrays for the following preferences inside arrays.xml
You have to set default and the default has to be one of entryValuesList strings-->
<!--Example of simple Thumbnail preference with no additional attributes-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ThumbnailListPreference
android:defaultValue="1"
android:key="test_thumbnail_key"
android:title="Simple thumbnail preference"
app:drawableArray="@array/thumbnail_drawables"
app:entryList="@array/thumbnail_items"
app:entryValuesList="@array/thumbnail_values"
app:dependentValue="2"/>
[COLOR="darkgreen"][I]<!--Example of Thumbnail preference which calls to kill app upon selected item-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ThumbnailListPreference
android:defaultValue="2"
android:key="test_thumbnail_kill_app"
android:title="Kill app thumbnail preference"
android:dependency="test_thumbnail_key"
app:drawableArray="@array/thumbnail_drawables"
app:entryList="@array/thumbnail_items"
app:entryValuesList="@array/thumbnail_values"
app:isSilent="false"
app:packageNameToKill="com.android.systemui"/>
IntentDialogPreference
Custom attributes:
app:intentSeparator - to allow you to set the char which will separate the package name from activity name in the intent component name
app:showSearch - boolean attribute which determines whether search field will be available in the dialog window. By default it's TRUE. If you want no search, set to FALSE
Code:
[COLOR="DarkGreen"][I]<!--The following preference is a special preference that's called IntentDialogPreference
This preference allows you to choose an app from the list. it also conveniently includes search field
This preference writes into database what's called component name for specific system needs.
When we want to call an app in android, we need to provide some information as to which app we want to launch
and which activity inside that app we want to lunch.
Launching app by combination of those is called explicit intent. Explicit intent needs 2 things to run an app:
1. Package name
2. Activity or service name
This preference is most useful for launching an specific app based on info you can fetch from database
For example on double click on home key
Intent dialog preference puts the info for explicit intent in a string. First package name, then separator, then activity name
You can use any separator you want. The default separator is "##"
But as you can see in following example we set the separator to be forward slash "/"
The separator depends on how you build the mod in smali for your needs.
Any kill app or reboot device attributes are applicable here as well-->
[/I][/COLOR]
[COLOR="darkgreen"][I]<!--This specific IntentDialogPreference has defaultValue set to Settings app.
You DO NOT need to set default. Only if you want to. But it is in most cases not necessary and even not that good.
This is just an example. When you run this, you will see that the preference has an icon of the chosen app on the right
and a name of the app set as summary. When you choose a new app, those things change-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.IntentDialogPreference
android:defaultValue="com.android.settings/com.android.settings.Settings"
android:key="test_intent_with default"
android:title="Select Test App with default"
app:intentSeparator="/"/>
[COLOR="darkgreen"][I]<!--This IntentDialogPreference comes with no default and no separator. So default separator will be applied "##"
and it also has no search showing-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.IntentDialogPreference
android:key="test_intent_without default"
android:title="Select app, no default, no search, ## separator"
app:showSearch="false"/>
[COLOR="darkgreen"][I]<!--This preference will prompt to reboot device upon selection
This is useful if f.e. you use it to set default app to open when home button is double clicked
Reboot is advised but not necessary immediately. So user will be shown a dialog to let them know they need to reboot
And they can reboot immediately or later-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.IntentDialogPreference
android:key="test_intent_without_default"
android:title="Select app and reboot device"
app:intentSeparator="/"
app:rebootDevice="true"
app:showSearch="true"/>
MyEditTextPreference
Code:
[COLOR="DarkGreen"][I][B] <!--Edit text preference is a dialog preference that allows you to enter custom text-->[/B][/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.MyEditTextPreference
android:defaultValue="test"
android:key="test_edit_text_key"
android:title="Input custom text"/>
​
3. Special Preferences
OpenAppPreference
Custom attributes:
app:componentName - string type attribute to provide package name and desired activity name to open installed app. Please pay attention to instructions in code.
Code:
[COLOR="darkgreen"][B][I]<!--The following category shows usage of special preference we use to open an app based on component info
All you need to provide for this preference is package name and activity name separated by forward slash "/" like shown below
We will split the component info into components and check if the app is installed
if it's installed, we will show the app icon as preference icon and app name as title
If the app is not installed the preference is automatically removed from the list.
You can set your own summary to explain about the app.
If you wish to show a custom icon for that app shortcut or have custom title,
if you wish to use custom icon or custom title, like you would do normally with preference,
You are free to use android:title and android:icon attributes.
Our class will then use the items you chose instead of the application title and icon.
This WILL NOT affect the intent for opening application. It's a cosmetic measure for your convenience.-->[/I][/B][/COLOR]
<PreferenceCategory
android:title="Shortcut to apps preferences">
[COLOR="darkgreen"][B][I] <!--Example of simple app shortcuts. If those apps are not installed, the preferences will not show-->
[/I][/B][/COLOR] <com.wubydax.romcontrol.v2.prefs.OpenAppPreference
android:summary="Application to browse your files, including root files"
app:componentName="com.speedsoftware.rootexplorer/com.speedsoftware.rootexplorer.RootExplorer"/>
<com.wubydax.romcontrol.v2.prefs.OpenAppPreference
android:summary="Control samsung's toolbox, turn it on or off, choose available apps and rearrange them"
app:componentName="com.wubydax.toolboxsettings/com.wubydax.toolboxsettings.ToolboxSettings"/>
[COLOR="darkgreen"][B][I] <!--Example of OpenAppPreference with custom title and icon-->
[/I][/B][/COLOR] <com.wubydax.romcontrol.v2.prefs.OpenAppPreference
android:summary="Choose what app or shortcut to open when TW launcher is being swiped to the magazine page"
android:title="Shortcut to GearTWSwipe"
android:icon="@mipmap/ic_launcher"
app:componentName="com.wubydax.geartwswipe/com.wubydax.geartwswipe.ResetDialogActivity"/>
[COLOR="darkgreen"][B][I] <!--Open app preference with only cuctom title and the icon which is loaded from the app-->
[/I][/B][/COLOR] <com.wubydax.romcontrol.v2.prefs.OpenAppPreference
app:componentName="eu.chainfire.supersu/eu.chainfire.supersu.MainActivity-Material"
android:title="Chainfire's SuperSu App"
android:summary="Manage root permissions for apps and services"/>
</PreferenceCategory>
UriSelectionPreference
Code:
<PreferenceCategory
android:title="Select image preferences">
[COLOR="darkgreen"][B][I]<!--Select image preferences allow the user to select any image from the gallery.
The uri for that image will be written into the database
Android can fetch images based on their uri (universal resource identifier).
A type of uri that you all know is called URL, which is a web address.
Uri for database is the "address" of an item inside the database.
In android we have Media database, which hosts info about media items. In our case we are interested in images.
Upon clicking this preference a Gallery will launch, upon selecting image, it's uri will be written into database.
In your mods you can fetch the string, convert it to Uri and set that image as background to anything you want.
We use this method for setting custom image in our mod for background to notification panel-->[/I][/B][/COLOR]
<!--Those are examples of simple uri selection preference. The icon for them will be the selected image preview
You need to set title and key. That's it.-->
<com.wubydax.romcontrol.v2.prefs.UriSelectionPreference
android:key="test_image_selection_key_2"
android:title="Select Image 2"/>
</PreferenceCategory>
RunScriptPreference
Custom attributes:
app:scriptFileName - string type attribute to provide script name to run, including the .sh extension.
app:showConfirmDialog - a boolean type preference, dtetermining whether a warning dialog will be shown before executing the script. we have had this request for previous version, since users sometimes hit script preference by mistake and it executes immidiately. By default this boolean is TRUE. So for any script a warning dialog will show. Youc an set it to FALSE to execute without warning.
app:rebootOptions - enum type attribute:
Sometimes you will perform actions in script which will require a device reboot to take effect
For this purpose we created this attribute, which can take 3 values:
1. None - this is default. You do not need to specify "none". if you don't specify rebootOptions it will always be "none"
This means reboot is not required upon running script
2. Optional - this means that the execution of this script is ok without immediate reboot,
but for the action to take effect, reboot is required. if you set rebootOption to "optional",
upon successful script execution a user will be presented with a dialog.
A dialog has 2 buttons: reboot now or reboot later.
Use this option ONLY if reboot is required for action to take effect and reboot is not VITAL. Meaning no app will FC without reboot.
3. Imminent- sometimes you will want to run scripts which replace key system components, such as entire apk
or even jar files. When a script like that is executed, you want immediate reboot. Because other wise the app in question
can throw FC. Most of you from what we have seen, use reboot option for scripts like these at the end of the script.
You NO LONGER HAVE TO. We will handle the reboot for you ONLY if the script is executed successfully and "imminent" option was chosen.
It is nice to WARN the user that their phone will reboot after running the script.
That is why if you choose app:rebootOptions="imminent" a dialog will be shown to the user once they click on preference.
This dialog will warn them that upon script execution their device will reboot
If you use this option, once the script is done we will execute the reboot. Make sure you have your app in priv-app before testing this. It will need reboot permissions. Please read the gradle explanation 2 posts above, regarding those permissions.
DO NOT use "reboot" or "kill zygote" commands at the end your scripts. Do yourselves and your users a favour and stop using those all together.​​
Code:
[COLOR="darkgreen"][I][B]<!--Running scripts in rom modding is no silly business.
We need shell scripts for purposes that can vary from writing a line into a file on sd,
through replacing sound files and host files,
to as far as replacing entire apk and jar files.
Because shell scripts can vary in their complexity, we created a special preference that runs shell scripts.
The major component in this preference is the scriptName attribute. The script name should be given in full,
as string, including extension (.sh).
The code for the preference knows where your scripts are found. It will locate the script if it's found there
and execute it.
if script execution fails, a number is being shown. That means the exit code of a script is not 0.
That means something is wrong in the script.
If the script is executed properly, a toast will be shown saying "Executed successfully"-->[/B][/I][/COLOR]
<PreferenceCategory
android:title="Run script preferences">
[COLOR="darkgreen"][B][I]<!--This is the basic script preference. It will jujst run a script.-->[/I][/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.RunScriptPreference
android:title="Execute script with prompt"
app:scriptFileName="simple_test.sh"
android:summary="This action will throw warning dialog before executing script"/>
[COLOR="darkgreen"][I][B]<!--Because of the radical nature of running shall scripts with su,
We included a dialog which is shown when a user clicks on script preference
By default confirm dialog will be shown before executing eny script. If you wish to run a script without the warning dialog,
You need to specify the custom attribute that a dialog should not be shown.
We strongly encourage you to keep the dialog. It's better for your users to be sure they clicked on the right option-->[/B][/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.RunScriptPreference
android:title="Execute without prompt"
app:scriptFileName="simple_test.sh"
app:showConfirmDialog="false"
android:summary="This action will execute script without warning"/>
[COLOR="darkgreen"][I][B]<!--Script preference with optional reboot-->[/B][/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.RunScriptPreference
android:title="Script with optional reboot"
app:rebootOptions="optional"
app:scriptFileName="simple_test.sh"
android:summary="This action will write into a file on sd card and show dialog that reminds the user to reboot their phone at this time or later for the action to take effect"/>
[COLOR="darkgreen"][I]<!--Script preference with imminent reboot-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.RunScriptPreference
android:title="Script with imminent reboot"
android:summary="This action will run script which has reboot command at the end and warn user that reboot of device will follow the script execution immediately"
app:rebootOptions="imminent"
app:scriptFileName="simple_test.sh"/>
[COLOR="DarkGreen"][B][I] <!--We were asked by some developers to make a kill app option available for script preference
Therefore, you can also use the kill package attributes now, silent or with dialog,
for your script preferences.
The following RunScriptPreference will prompt killing contacts app f.e
P.s. you can set icons to your run script preferences like any other preference-->[/I][/B][/COLOR]
<com.wubydax.romcontrol.v2.prefs.RunScriptPreference
android:title="Execute and kill app + icon"
android:icon="@mipmap/ic_launcher"
android:summary="Upon finishing, this script preference will prompt a user to kill app, since we set the isSilent attribute to false"
app:packageNameToKill="com.android.contacts"
app:isSilent="false"
app:scriptFileName="simple_test.sh"/>
</PreferenceCategory>
ImageHeaderPreference
Custom attributes:
app:imageSource - reference type of attribute to set the image to show as header preference. The default size for image is width match_parent and height 200dp.
This is just one of those little things we made for fun, but it ended up being @tdunham 's favourite toy
Code:
[COLOR="DarkGreen"][I]<!--This is one of those little bonus thingies what we made for our beta-testers
and you all get to inherit it. It's a little preference class called ImageHeaderPreference
It allows you to choose and image as header for your preference screen.
Just to bring a little color and life into all those switches and checkboxes...-->[/I][/COLOR]
<com.wubydax.romcontrol.v2.prefs.ImageHeaderPreference
app:imageSource="@drawable/android"/>
Themes, About Us activity and changelog dialog
1. Themes:
1. There 2 built in themes: light and dark. In the navigation drawer, much like in previous version, you have a section under More options which is called "Set Theme".
2. Upon clicking it a dialog will pop up to allow theme selection.
3. The default theme is the light one. If you wish your default theme to be the dark one, please navigate to res/values/styles and find the following line (at the very bottom):
Code:
<integer name="default_theme">0</integer>
(yes, we put integer in styles (because we CAN), we're weird like that... LOL. It's for your convenience.​
4. To make the default theme the dark one, change 0 to 1.​
2. About Us activity - how to populate it:
1. Navigate to values/about_us_resources.xml
2. When you open it you have 3 sets of 3 arrays each. This idea is very similar to how you populated the navigation drawer items. Let's have a look:
Code:
<resources>
[COLOR="Teal"][B]<!--Contact info arrays-->[/B][/COLOR]
[COLOR="DarkGreen"][B][I] <!--In this array you will put the icons for contact information,
for example xda icon for your xda thread, site icon for your site, facebook icon and so on-->[/I][/B][/COLOR]
<array name="about_contact_us_drawables">
<item>@drawable/icon_2</item>
<item>@drawable/icon_1</item>
<item>@drawable/icon_3</item>
</array>
[COLOR="darkgreen"][B][I]<!--In this array you will put the titles for your contact info items. Keep the order consistent between all 3 arrays-->[/I][/B][/COLOR]
<string-array name="about_contact_us_text">
<item>Facebook</item>
<item>Our Site</item>
<item>XDA</item>
</string-array>
[COLOR="darkgreen"][B][I]<!--In this array you will put the titles for the URL strings that will open once a user clicked on the item-->[/I][/B][/COLOR]
<string-array name="about_contact_us_links" translatable="false">
<item>https://www.facebook.com/</item>
<item>https://www.google.com/</item>
<item>http://forum.xda-developers.com/</item>
</string-array>
[COLOR="teal"][B]<!--Team info arrays-->[/B][/COLOR]
<array name="about_team_drawables">
<item>@drawable/icon_5</item>
<item>@drawable/icon_6</item>
<item>@drawable/icon_1</item>
</array>
<string-array name="about_team_names">
<item>Master Yoda - wise and talented lead developer</item>
<item>Luke Skywalker - one handed theme master</item>
<item>Darth Vader - dark theme master</item>
</string-array>
<string-array name="about_team_links" translatable="false">
<item>https://www.facebook.com/</item>
<item>https://www.google.com/</item>
<item>http://forum.xda-developers.com/</item>
</string-array>
[COLOR="teal"][B] <!--Credits and thanks info arrays-->[/B][/COLOR]
<array name="about_credits_drawables">
<item>@drawable/icon_1</item>
<item>@drawable/icon_3</item>
<item>@drawable/icon_4</item>
<item>@drawable/icon_2</item>
<item>@drawable/icon_6</item>
<item>@drawable/icon_5</item>
</array>
<string-array name="about_credits_names">
<item>Star Trek - for being ultimately better than Star Wars</item>
<item>Jean-Luc Picard - for making us crave hot earl-grey tea even in the middle of the summer</item>
<item>Data - for running on the best rom. Google, we still are waiting for THAT android version</item>
<item>Janeway - for being a normal person and drinking black coffee</item>
<item>Q - for reminding us that you can live forever and still look great</item>
<item>Worf - for teaching us to love Klingons. It was NOT easy</item>
</string-array>
<string-array name="about_credits_links" translatable="false">
<item>https://www.facebook.com/</item>
<item>https://www.google.com/</item>
<item>http://forum.xda-developers.com/</item>
<item>https://www.facebook.com/</item>
<item>https://www.google.com/</item>
<item>http://forum.xda-developers.com/</item>
</string-array>
</resources>
3. As you can see from the code above it's very simple. Find images you want to use, You don't need to make them round. They will be made round on runtime.
4. Replace the demo information in our arrays with your own, including images reference, titles and links. Make sure the lenghts of 3 arrays in each category are equal.
5. You can make as many or as little items as you want. As long as the length of drawable array equals to length of titles array and equals to length of links array in single category.
6. All the magic is done in java for you. Just populate arrays and RUNNNN​
3. Changelog Dialog - how to populate it:
1. Navigate to /res/values/changelog_resources.xml
2. Inside you will find 1 string and 1 string array. Let's have a look:
Code:
<resources>
[COLOR="Teal"][B]<!--Do not forget to include this in any locale specific folders for translation-->[/B][/COLOR]
[COLOR="Green"][B][I]<!--In the following array put your changelog items
Take as many lines as you need.
Add as many items as you want or delete some if those are too many
This order is how they will appear in the dialog
Make any order you want from top to bottom-->[/I][/B][/COLOR]
<string-array name="changelog_items">
<item>Some changelog thing lkjh l lkjh slkjh lkjh s,mnb lkjhs lkjh poiuy slkjh</item>
<item>Another changelog thing ;lkj d;lkj ;lkjs ;lkj ;lkj s;lkj ;lkj s;lkj ;lkj ;lks ;lkj ;lkj</item>
<item>Some more changelog things</item>
<item>Some even more changelog thing</item>
<item>And another changelog thing ;lsj; lkjs ;lkj ; lkj;lsjk ;sklj s;lkj s;lk js;lkj s;lkj</item>
<item>How many changelog things</item>
<item>What a long changelog!!!</item>
<item>Is it twenty already?</item>
<item>Are we there yet?</item>
<item>Live long and prosper</item>
<item>So say we all</item>
<item>Patience you must have</item>
<item>Great scot!!!</item>
<item>No disassemble…</item>
<item>Almost there</item>
<item>Done with changelog</item>
</string-array>
[COLOR="green"][B][I] <!--This will be the dialog title.
Put your own rom version and name.
Have fun-->[/I][/B][/COLOR]
<string name="rom_version_for_changelog">build v1.0 6thgearrom</string>
</resources>
3. Fill and up with your own items. Enjoy!​
Backup and Restore functionality
Backup and restore is done on a background thread using a service. Once the service gets intent with certain action it performs the required activity and shuts down.
The service can be called with wither backup action or restore action. In each case it will act differently.
1. How does that work - BACKUP:
When a request for backup is passed to the service, it does several things:
1. Checks if on your sdcard there exists a folder called RomControl and checks if the folder contains subfolder backups. If they don't exist, they are being created.
2. In our data f folder in data/data/com.wubydax... we have a shared_prefs folder. Inside it we have preference xml files for all of your preferences.
3. We iterate through those files and read them line by line, and once they are read, we take the keys and read the actual database value for that key
4. Then we write those values with their corresponding keys into a new backup file
5. Each backup file has a new name. You can see how it's formed here:
Code:
String currentDate = new SimpleDateFormat(getString(R.string.backup_file_prefix_date_format), Locale.ENGLISH).format(Calendar.getInstance().getTime());
String fileName = currentDate + "_" + Build.DISPLAY;
String backupFileName = fileName + getString(R.string.backup_file_suffix);
File newBackupFile = new File(Constants.BACKUP_FOLDER_PATH + File.separator + backupFileName);
As you can see we use 3 components for name:
a. Current date and time up to munites
b. The display id from the build.prop
c. suffix RCBackup​
That is so the users can differentiate between different backups from different roms or versions​
6. It also backs up the file preferences (see the preference explanation post for that)
7. The service finishes and throws a toast that it's done and the file can be found in the backup directory​
2. How does that work - RESTORE:
1. During restoring action, the main activity closes. It also says so in the warning dialog which appears right before restore is activated.
2. We made it so to make sure no onPreferenceChangeListener is triggered for any of your preferences. We also want a clean restart of the activity once the restore is done, so all the items can be loaded from the database, which has been updated by the restore process.
3. During restore we read the selected backup file, break it into pieces and write the values to database. When the activity is reloaded, preferences read from databases and update their own values.
4. For file preferences, during restore process we delete the files saved previously and only create the ones contained in backup file.​​
reserved 8
reserved 9
reserved 11
reserved 12
This blows away the original version folks.
Cant wait for it to go live. And couldn't resist being the first poster as well.
tdunham said:
This blows away the original version folks.
Cant wait for it to go live. And couldn't resist being the first poster as well.
Click to expand...
Click to collapse
You are simply the best ???
Sent from my SM-G920F using Tapatalk
Wow. This is amazing. Thank you for your time and sharing it. It's just another treasure after v1.0.
Sent from my SM-G935F using Tapatalk
Waiting
Wooooow , loooong time waiting for this , now time for reading & starting ready for it xD , as usual thanks for ur awesome work , ???
thereassaad said:
Wooooow , loooong time waiting for this , now time for reading & starting ready for it xD , as usual thanks for ur awesome work , ???
Click to expand...
Click to collapse
Happy to see you here! Don't read yet. Only posts 1, 2, 3, 4 and 6 are finalized.
Sent from my SM-G920F using Tapatalk
Wow, I am loving how this version is going to handle killing apps. And about custom preferences I am a bit confused but I guess I should wait till it's out and see how it would work. Setting default_theme it's just mind blowing! Guys before the source is out I think it would be a good idea to try reading and understanding what is outlined in OP I didn't use to sign my rc but it's explained clearly how to do it in studio. :good:
WOW!
As I have said before, you and Wuby are the most precious thing to us, the ROM devs
What an incredible update!
Sure, I have a lot of work to do on rom control v2, but I have you on my side -that's a good thing hehe.
Amazing work! I am sure my users enjoy it as well.
Keep it up, but make some time for me too
Sent from my SM-G900F boosted by PhoeniX ROM

Recompiling with additional resources and activities

Hello All,
I have an application that I want to add some features to in the form of an additional activity. I have decompiled it with APK tool and attempted to add my own smali files (from the decompiled 2nd app that I developed). I immediately run into problems with the dependencies of my app being different than those of the original app. For example, my app uses the google Easy Permissions lib to ask for permissions. What is the right strategy to help de-conflict the res/values/*.xml files between two apps that both have their own resources? Are there any tools that can assist in this? What about layout and drawable resources?
I started writing a python script to merge public.xml and the others, re-map the ID's for those resources, and then search the smali files to change the values there. That seems error-prone, and I am not even sure if that is the right thing to do.
I had a second thought that perhaps aapt2 compilation of resources could perhaps be modified to give me a different package ID for the app I created and control source to (such as 0x80... instea of 0x7f...) but I am not sure exactly how to go about that, or if that would even work either
Any advice or tools I should be looking at?

[INVESTIGATION] Android Pie - Multitasking Gesture

I'm opening this thread because I want to work out the multitasking gesture API implemented in Android Pie (I think DP3+.)
I'm going to try reverse-engineering the APK but I'm including a dumped copy here for anyone else who wants to have a shot at it.
(Note to Moderators: I have no idea if this kind of thing is allowed - if not, you can just delete the thread.)
Quick update; I reverse engineered some of the APK with Fernflower.
The code is heavily obfuscated but I think I found the relevant code. (This is just a quick glance as I don't have the time to go through it thoroughly.)
The ZIP contains:
com/android/systemui/shared:
recents/...*
system/...*
R.java
(I don't want to type out the whole list)

Categories

Resources