[Resolved] [Q] Finding the right activity? - General Questions and Answers

I installed the MotoBlur style Atrix Clock HD skin for the EZ Weather app. It works pretty great, except the actual weather application sucks. So using tasker, i intercept the app being opened and i force it closed and then open an app of my choice. Peachy.
Well, all the other apps suck too. The one i like the most is the overlay that comes with HD Widgets.
That said, I'd like to make it so that the HD Widgets' overlay comes up instead of the default app. As you read above, I already know how to do this. The problem is that i can't find the right "activity" (don't know if this is the proper jargon) to launch when i want to do this override. I made a video which shows that i can't find the "activity" that i want. I can select them, but these are all just configuration activities and not the weather activity.
Knowing that a press on the widget produces the weather app, but also knowing that none of the activities reflect that particular desirable screen are showing up when i search them, how can i find the correct activity so that i can point to it using tasker? Or is it something else i should be doing?

no way!! no one knows this stuff???

Angry Black Man said:
no way!! no one knows this stuff???
Click to expand...
Click to collapse
You want to find the activity of the app coming on ? What is the weather activity you're looking for ? you don't know the name , what does it do ?
The main activity is what's used when the app first opens

It's all there in the video and my description. Keep in mind, I don't know what I'm trying to do which is why I'm asking the question. Carefully read my post and it describes exactly what I'm trying to do and my video shows the impediment to that.

I don't know what it is. The things I see are.
Package ,
cloudytv.hdwidgets
Activity ,
cloudtv.hdwidgets.activities.MainActivity
Component ,
ComponentInfo{cloudtv.hdwidgets/cloudtv.hdwidgets.activities.MainActivity}

@Angry Black Man,
I know precisely what you're asking for, and it's actually surprisingly difficult. Here's the best and most convenient method I've come across for finding the names of the activities in packages.
1. Download and install (even if temporarily) this version of ADW Launcher.
2. Follow this sequence of taps: Menu > Add > Custom shortcut > Pick your activity > Activities.
3. You are now on a screen with a list of all the apps you have installed on your device. This includes in /data/app and /system/app.
4. Find the app that you need the activity name for and tap on its small downward-pointing arrow on the far left side.
5. This opens a list of all of the activities available for the app. Using the labels and your logical reasoning, find out which activity is the one you need.
6a. From here, you have two choices. Choice 6a. (this one) is to tap on that activity, tap "OK", and make a shortcut on your homescreen directly to the activity. Or...
6b. Choice 6b. is to memorize/write down the activity you want to execute in the terminal (remember the period "."), exit the Custom shortcut dialog, open up the terminal and execute this:
Code:
su
am start -n [package name found in /data/app or /system/app]/[activity name you memorized/wrote down]
For example, to execute the activity to start Developer Options, I would use this:
Code:
su
am start -n com.android.settings/.DevelopmentSettings
Hope this helps!

Thank God. Someone with some actual technical understanding! Well, I dove in, but I just couldn't crack this egg. I did see more activities than I was able to get to in my video, but in adw, I keep getting " app not installed" errors. I then installed secure settings for tasker and got to the activities and was able to get one of my Samsung weather activities to work, but I simply can't find the hd widgets activity. I tried weirdly named activities within hd widgets that works crash immediately.. Are there " hidden" activities?

Angry Black Man said:
Thank goodness. Someone with some actual technical understanding! Well, I dove in, but I just couldn't crack this egg. I did see more activities than I was able to get to in my video, but in adw, I keep getting " app not installed" errors. I then installed secure settings for tasker and got to the activities and was able to get one of my Samsung weather activities to work, but I simply can't find the hd widgets activity. I tried weirdly named activities within hd widgets that works crash immediately.. Are there " hidden" activities?
Click to expand...
Click to collapse
No, there aren't - ADW without a doubt provides the full list. However, many activities are dependent upon other ones. They just f/c if you start them individually, but if used in conjunction with other activities, they work properly.
Only problem with that is that the only real way to launch multiple activities at the same time is to launch the entire package (app). This is even harder with widgets, however, because of how they work differently than regular apps. That's why you're getting the "App not installed on your phone" error - because the Android system gets finicky when it tries to launch a widget activity.

I figured out a solution!!!!!
WHEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Got it
Okay, so understanding that I had the right "jargon" (the word "activity") i focused my search on this type of word. I even went to far as to ask the developers directly how to trigger the intent:
[email protected] said:
Hi Aaron,
I believe this is tied to an action (my apologies as I don't know the exact code terminology) - the weather app will launch only when you tap on your weather hotspot. Opening the app from the icon will only open the editor. To link this in another app, you'll need to replicate the action of tapping on the hotspot in order to link directly to weather.
Thanks,
Sol
Click to expand...
Click to collapse
...which didn't tell me anything I didn't already know. Useless.
So i keep plugging along. I installed "Secure Settings" which as I mentioned exposed "more" activities in apps, but led to my question of finding "hidden" activities (one's that i simply couldn't find in a menu someplace). Every time i searched "activity logger" on google, i kept finding stuff about keyloggers and *actual* activity loggers. ARGH!
I decided then to search for "adb activity logger" to try and make the search very specific to app design. I ended up at this stackexchange discussion titled "View the Task's activity stack". The accepted solution (God bless stack exchange for not polluting the internet with useless, non-peer reviewed information) suggested using adb to dump all the activities on the device. Further (thank you stackexchange solution comments!!!!!) someone suggested grepping only the information i needed.
On windows, the grep equivalent is "find", so i just made the necessary modifications to the command:
Code:
adb shell dumpsys activity | find /i "cloudtv"
which shat out:
Code:
* PendingIntentRecord{4368c4e0 cloudtv.hdwidgets broadcastIntent}
* PendingIntentRecord{436dfdf8 cloudtv.hdwidgets broadcastIntent}
* PendingIntentRecord{4477ecb0 cloudtv.hdwidgets startActivity}
#19: BroadcastRecord{43cd02a8 u0 cloudtv.UPDATE_TIME}
act=cloudtv.UPDATE_TIME flg=0x10
#19: act=cloudtv.UPDATE_TIME flg=0x10
-> 15158:cloudtv.hdwidgets/u0a259 s1/1 u0/0 +5h16m5s671ms
* ServiceRecord{440b7d68 u0 cloudtv.hdwidgets/.services.WidgetUpdaterService}
app=ProcessRecord{430c05b0 15158:cloudtv.hdwidgets/u0a259}
* Recent #4: TaskRecord{45de8b40 #90 A=cloudtv.hdwidgets U=0 sz=0}
Proc #14: cch+4 B/ /S trm: 0 15158:cloudtv.hdwidgets/u0a259 (cch-started-ui
-services)
C:\Users\User>adb shell dumpsys activity | find /i "cloudtv"
* PendingIntentRecord{4368c4e0 cloudtv.hdwidgets broadcastIntent}
* PendingIntentRecord{436dfdf8 cloudtv.hdwidgets broadcastIntent}
* PendingIntentRecord{4477ecb0 cloudtv.hdwidgets startActivity}
#3: BroadcastRecord{45f650f8 u0 cloudtv.hdwidgets.WEATHER_UPDATED}
act=cloudtv.hdwidgets.WEATHER_UPDATED flg=0x10 (has extras)
#4: BroadcastRecord{45f65008 u0 cloudtv.hdwidgets.WEATHER_UPDATED}
act=cloudtv.hdwidgets.WEATHER_UPDATED flg=0x10 (has extras)
extras: Bundle[{activityState=create, activityPackageName=cloudtv.hdwidgets}
]
#43: BroadcastRecord{43cd02a8 u0 cloudtv.UPDATE_TIME}
act=cloudtv.UPDATE_TIME flg=0x10
#43: act=cloudtv.UPDATE_TIME flg=0x10
-> 15158:cloudtv.hdwidgets/u0a259 s1/1 u0/0 +5h16m28s216ms
* ServiceRecord{440b7d68 u0 cloudtv.hdwidgets/.services.WidgetUpdaterService}
app=ProcessRecord{430c05b0 15158:cloudtv.hdwidgets/u0a259}
TaskRecord{45ef1980 #93 A=cloudtv.hdwidgets U=0 sz=1}
Intent { act=cloudtv.hdwidget.weather.SHOW_WEATHER_ACTIVITY flg=0x10000000
cmp=cloudtv.hdwidgets/.activities.MainActivity (has extras) }
Hist #0: ActivityRecord{443bdf18 u0 cloudtv.hdwidgets/.activities.MainAc
tivity t93}
Intent { act=cloudtv.hdwidget.weather.SHOW_WEATHER_ACTIVITY flg=0x1000
0000 cmp=cloudtv.hdwidgets/.activities.MainActivity bnds=[23,1179][248,1336] (ha
s extras) }
ProcessRecord{430c05b0 15158:cloudtv.hdwidgets/u0a259}
TaskRecord{45ef1980 #93 A=cloudtv.hdwidgets U=0 sz=1}
Run #0: ActivityRecord{443bdf18 u0 cloudtv.hdwidgets/.activities.MainAct
ivity t93}
mResumedActivity: ActivityRecord{443bdf18 u0 cloudtv.hdwidgets/.activities.M
ainActivity t93}
mFocusedActivity: ActivityRecord{443bdf18 u0 cloudtv.hdwidgets/.activities.Mai
nActivity t93}
* Recent #0: TaskRecord{45ef1980 #93 A=cloudtv.hdwidgets U=0 sz=1}
Proc # 0: fore F/A/T trm: 0 15158:cloudtv.hdwidgets/u0a259 (top-activity)
and there, in all that junk, i found:
Code:
Intent { act=cloudtv.hdwidget.weather.SHOW_WEATHER_ACTIVITY flg=0x10000000
A quick search on how to fire activities from tasker, and i had finally solved the problem!

ИΘΘK¡€ said:
@Angry Black Man,
Code:
su
am start -n [package name found in /data/app or /system/app]/[activity name you memorized/wrote down]
For example, to execute the activity to start Developer Options, I would use this:
Code:
su
am start -n com.android.settings/.DevelopmentSettings
Click to expand...
Click to collapse
What does the -n do ? I can start it without using that and don't see anything that it does.
I enter , am start ,
and it shows list of commands for that, I don't see what -n is for.

@ryan012, I actually don't know for sure, but the syntax listed says [-n <component>] about the "-n" tag. You can look for more info here.

Related

Sending calls to running GUI apps via CLI

This is /sort/ of a development question; if the mods feel it's more properly in Q&A, please move it.
First off, a little disclosure; "IANAP".
Okay, here goes:
Currently I am trying to create what ought to be a /very/ simple script using "am" (as in; am start -a blahblah -n blahblah/.blah ) in order to invoke an activity for a specific application. Unfortunately, apparently the activity can only be called viably from //within// the application.
The app in question is "redditisfun" ( http://github.com/talklittle/reddit-is-fun ). The activity in question is ".InboxActivity". So far, I can get the first bit of code to pull up the app, but the second bit fails out due to lack of permission.
1)
Code:
am start -a android.intent.activity.MAIN -n com.andrewshu.android.redditdonation/.RedditIsFun
2)
Code:
am start -a android.intent.activity.MAIN -n com.andrewshu.android.redditdonation/.InboxActivity
I've tried it with "broadcast" rather than "start" -- that throws no errors, but simply does nothing. (logcat shows no activity that I can see.)
So here's my question; how does one send a system call to an app that is already running, using am? I am afraid that none of the documentation I've yet found says anything at all about this.

[Q] Development Question - NEWBIE - Android

Hi, I am just starting developing and I have been playing with the notepad sample code on android developers (the ones you get with the SDK). I have added it to the bare-bones of my app, and the first Activity opens fine and the menu works, but when the first activity opens, the debugger gives me the error
Code:
Failed to find provider info for com.example.notepad.provider.notepad
I changed all the references to com.example... to my package name that I could find, but none of them referred to the "provider"
The debugger also says that the activity is starting but I get an Activity not found exception.
It is looking for dat=content://com.example.notepad.prover.notepad/notes
I have tried to search for this reference in all the files, but I am not seeing it (or rather the search and find parts of Eclipse are not finding it.
What am I missing?
Sorry, I can do Java Applets, but this Android thing is completely new!

[TUT] Tasker – Google Calendar Widget (via Minimalistic Text) | Optional AutoNav V2

Profile Aim
Tasker reads your calendar creating a home screen widget via Minimalistic Text. Reacting to a future ‘meeting’ entry, it queries Google to find out the route information and journey time. Using the journey time information and meeting start time, it calculates what time you will have to leave and loads Sav Nav with the preselected route 5 minutes before you are due to depart.
Now FULLY Functional
Whilst creating the ‘Ultimate Alarm Clock’ I wanted the speech engine to read out the details of my meetings for the coming day from my calendar. I was a little disappointed that Tasker did not yet have the functionality to do that and despite delving into the calendar data base files; I could not find a way to achieve it. Damn.
When Tasker is able to read calendar entries in future releases, the tasks described below can be easily adapted to make sure you have a ready to go profile, but in the mean time, and I hope as always, this tutorial is full of handy Tasker tips and tricks…
New to Tasker? Download your free trial here
MT Google Calendar Widget only
If you don't want the AutoNav, I've included a download below with just the MT widget in. There is therefore only limited preparation you'll need to perform:
* Download the Minimalistic Text (MT) Plugin free from the market.
* Following the simple instructions in this link and get the private url output of your calendar in xml format. Remove the https://www. from the beginning and test it in your device's browser.
* At the end of the URL after 'basic' put '?max-results=3&futureevents=true&orderby=starttime&sortorder=ascending' (without the ' ) and that should order the calendar by the next three events.
* Edit action #2, #3 & #4 in GCAppTime to replace the time-zone abbreviation with that relevant to your location. It currently splits at 'BST'. Check the output file googlecal.txt on your storage card if you're unsure.
Head to the download link!
Initial Full Preparation (very simple)
* A Gmail account and calendar.
* Download the Minimalistic Text (MT) Plugin free from the market.
V3 PREP: Following the simple instructions in this link and get the private url output of your calendar in xml format. Remove the https from the beginning and test it in your device's browser. Tasker will be extracting your calendar data from this.
At the end of the URL after 'basic' put '?max-results=3&futureevents=true&orderby=starttime&sortorder=ascending' (without the ' ) and that should order the calendar by the next three events.
So you don't have to change the all the icons I've used, download them directly to your device from here and unzip to folder level inside sdcard/Tasker/.icn
Overview
We are going to use the Google calendar private xml output to provide details of our up and coming calendar events. Tasker will react to a keyword of *meeting* within the title field and extract the relevant details to populate a widget and get your sat nav ready to take you there, loading up when you are due to leave.
First Shortfall (doh!)
Tasker does not yet have the functionality to trigger a profile when a created variable such as %MEETING_DEPARTURE_TIME = %TIME (current time). As a work-around, a new calendar entry is created to trigger the navigation to load.
Secondary Preparation (very simple)
We have to structure the content within the Google calendar so that it is constant. The XML feed will need to be split apart to extract the information we need. Tasker cannot adapt to changes in format, so until you are comfortable enough with the variable splits that take place, you’ll need to follow these instructions.
In the ‘title field’, put this text: Meeting - Bank Manager
In the ‘where field’ you want to put a location that is obvious to Google Maps and wouldn’t give you choices if you put the same query in a browser.
Example: in the ‘where field’, put: Oxford+UK
Do not leave spaces between the location information. Join them with ‘+’ symbols. Post codes work in the UK too, but I’m not sure about ZIP codes etc abroad. Just experiment in a browser first if needs be.
The ‘description’ field (although extracted) is not used in these profiles, so you can populate that how you like.
Ensure you have at least one of the above formatted events and another two calendar entries of any kind.
Installation
Download and import the following 12 tasks:
GCAppLoc
GCAppDesc
GCAppTime
GCAppTit (lol?)
GCGetJD
GCJD
GCJT
GCAT
GCJTMaths
GCNavMaths
GCEntry
GCMT
Download and import the following 2 profiles:
Google-Calendar
Google-AutoNav
The .zip folder also contains the file Google_calendar_mtpref. This should be dragged into the sdcard/MinimalisticTextPreferences folder. It can then be selected in the MT Preference Manager or by selecting the 'restore' option when creating a new MT widget.
Customisation
Set the profile GoogleCalendar to however often you wish to pull the feed.
Edit action #2 in GCgetDatato the URL of your private XML feed. Don't forget drop the https://www. from the beginning and add the URL extension detailed above to the end.
Edit action #4, #5 & #6 in GCAppTime to replace the time-zone abbreviation with that relevant to your location. It currently splits at 'BST'. Check the file Googlecal.txt if you're unsure
Edit action #5 in GCJD to replace the splitter ',UK' with your country. You may need to view this in a browser to see how Google handles this.
Edit action #22 in GCEntry to the calendar you wish to use for the reminder.
That’s it!
Testing
In each of the tasks after a STOP action, I've left in various 'flash' and 'list' actions that I used when creating the tasks. If anything goes wrong, you can drag these up the list to see where/why a task might be failing.
The tasks are numbered in the notification bar, so should something go wrong, you'll be able to see on which task the profiles failed.
Tick the profiles to active them and apply out of Tasker!
Make sure your data connection/wifi is turned on and ‘Use GPS satellites’ and ‘Use wireless networks’ is ticked under ‘Location & Security’ in settings. You’ll be getting a GPS fix, so get ready to hang out of a window!
Press 'test' in the task GCGetData and you're off!
The icons in the notification bar tick down from 11 until the departure time is displayed and then check your calendar for the entry that will trigger the navigation to start!
If you are testing multiple times, you'll need to variable set %GCNAV to 1 each time. If this variable is set to 2, Tasker will ONLY update the MT calendar widget.
Job done….
Tutorial & Task Explanation
Google-Calendar
The initial profile is trigger is time based. You can set it to update how every frequently you want the Minimalistic Text widget to refresh.
GCGetData
First up, this task pulls the XML feed from your calendar. The output is written to a text file sdcard/Googlecal.txt. You can view the file in an explorer to see the data it pulls.
GCAppLoc
Splitting apart the XML feed (having transferred it to a created variable %GCFEED for good housekeeping), we extract the three appointment locations and place them in:
%GCLOC1
%GCLOC2
%GCLOC3
GCAppDesc
As above, this time extracting the description field to:
%GCDESC1
%GCDESC2
%GCDESC3
GCAppTime
As above, placing the calendar entry date and time into:
%GCTIME1
%GCTIME2
%GCTIME3
GCAppTit (lol?)
The final splitting task, that gets us the three titles:
%GCTIT1 (lol?)
%GCTIT2 (lol?)
%GCTIT3 (lol?)
You'll notice at action #18 there is a GOTO IF %GCNAV = 2. This variable is set to 1 when the navigation calendar entry triggers. IF it is still set to 2, then Tasker knows you already have a pending navigation entry and won't create another one. The GOTO skips all of the other tasks and goes straight to refreshing the MT widget with the above data, before stopping.
Assuming %GCNAV isn't set to 2, the task continues and checks if each of the %GCTITs (lol?) MATCHES 'Meeting*' (the '*' being a wild card to allow further body text after). If it does, it sets the main %GCTIT (lol?) to its contents and is told to perform the task %GCGetJD.
You'll note that IF %GCTIT1 (lol?) does match 'Meeting*' the perform task action has a STOP on, so Tasker will not get to consider the contents of %GCTIT2 (lol?) & %GCTIT3 (lol?). This avoids multiple requests for navigation entries.
GCGetJD
If Tasker did find 'Meeting*' in the title fields, a location request is actioned as your assumed starting point (this will change in V3). Once the location information is received, Tasker needs to know which of the three %GCLOC# variables it needs to include in the URL as the destination.
This is achieved by asking on each HTTP GET action, IF the corresponding %GCTIT# (lol?) entry contained 'Meeting*'. Using the same GOTO principle as above, the correct %GCLOC# can be set to %GCLOC and is therefore requested in the URL for the direction details.
The output file is written to SDCard/Journey.txt which you can view with a file explorer should you wish.
GCJD
This task reads from the file Journey.txt and splits it to populate %JOURD with the journey distance.
GCJT
Similar to the above, this time we populate %JOURT with the journey time.
GCAT
Using similar GOTO and IF actions to previous tasks, we establish which of the calendar events is the meeting and populate the information to %CALDTD so we can manipulate it.
The start time of the calendar entry is used for the arrival time and after some variable splits, is set again to %CALDTD
Note: Variable splits can be difficult to understand at first. Often when testing, I add a 'Variable List' action followed by a STOP action after each split. This way I can see what is happening to the data when I split it and the Variable List that appears details all of the parts I may either wish to use or clear for good housekeeping.
GCJTMaths
This is where it started to get a little tricky... As structured as the data is, there are of course many eventualities when it comes to the possible journey time:
Code:
# mins
1 hour
1 hour 1 min
1 hour # mins
# hours
# hours 1 min
# hours # mins
Using the method I described earlier of listing the variables after each split, I had to look for constants and newly created variables that I could use to cope with each eventuality.
For example, the first split I do is at the instance of 'hour'. Looking above you'll see that we could end up with the following:
Code:
# mins ~ will create no further variables
1 hour ~ will create no further variables
1 hour 1 min ~ will create a variable of '1 min'
1 hour # mins ~ will create a variable of '# mins'
# hours ~ will create a variable of 's'
# hours 1 min ~ will create a variable of 's 1 min'
# hours # mins ~ will create a variable of 's #mins'
Splitting further again by the instance of 'min':
Code:
# mins ~ no further variables ~ no further variables
1 hour ~ no further variables ~ no further variables
1 hour 1 min ~ a variable of '1 min' ~ a variable of '1'
1 hour # mins ~ a variable of '# mins' ~ variables of '#' & 's'
# hours ~ a variable of 's' ~ no further variables
# hours 1 min ~ a variable of 's 1 min' ~ a variable of '1'
# hours # mins ~ a variable of 's # mins' ~ variables of '# min' & others
Scrolling through the task, I had to establish which journey time eventualities would lead to which data being populated to which variables! It gave me brain ache, but eventually I cracked with the help of plenty of IF statements and a GOTO action.
The result was having journey time hours (%JOURTDH) and minutes (%JOURTDM) separated into created variables.
GCNavMaths
Knowing my arrival time and the journey time, next up was to calculate what time I would need to depart. Unfortunately, simply subtracting one from the other isn't a possibility. An example arrival time of 14:30 with a journey time of 2 hours and 38 minutes may have Tasker trying to get you to leave at 12:-8; if at any time at all!
It's necessary to first deal with possible minus numbers and such issues as 3 hours before 01:00 not being at time of -2.00
Here's a working example:
If the appointment time is #:30 and the journey minutes are 40, then the we are after a departure time of #:50 rather than -10 if Tasker was left to its own devices. Seeing that the journey minutes are greater than (>) the arrival minutes, this gives us a chance to prevent the minus number occurring by adding 60 to the appointment minutes. This of course has to take place after the appointment time has been split apart into hours and minutes...
Code:
30 + 60 - 40 = 50 ~ The desired departure minutes
Using IF statements to establish whether the above scenarios are true, gives us the opportunity to take the action of adding 60 only IF journey minutes are greater than arrival minutes.. IF not, the action is skipped.
IF we've had to add 60 to the minutes, we can therefore deduce that we need to reduce the hour by 1. The exact same IF action above tells Tasker whether to perform this or not.
When we are finally left with separate departure time hours and minutes we need to variable join them into a time format. As a note, Tasker uses #.# rather than #:# as a time separator. Joining the hours and minutes using '.' would just be too easy wouldn't it... If the departure time is 02.09 in the morning for example, Tasker currently has them stored separately as 2 and 9. Joining them in this state would give us 2.9 which is no good of course...
We solve this issue by joining the hours to a leading zero IF they are less than 10, giving us '02'. We join the minutes to '.0' IF they are less than 10, or just '.' otherwise. We now have 02.09 stored in the created variable %DEPTD. Sorted.
GCEntry
It would be fantastic if the departure time above (%DEPTD) could be triggered when it equals the inbuilt time variable %TIME, but alas, that's not yet implemented in Tasker. The work-around to this is to trigger the navigation to start when a calendar entry becomes active with the departure details contained inside it.
The problem to this is that Tasker only enables you to set a calendar entry using 'minutes from now', so yes our example of 02.09 above is currently useless. I'm sure this will change in future releases so I persisted with GoogleNavMaths despite this, but regardless, next we have to convert the departure time into the number of minutes from now... Oh joy...
It involves a similar practice to GCNavMaths where we split the hours and minutes of the actual %TIME along with our example of 02.09, convert them both into minutes and find the difference between them. For the example below, lets say the current time is 19.38.
Code:
02.09
02 * 60 = 120
120 + 09 = 129
19.38
19 * 60 = 1140
1140 + 38 = 1178
129 - 1178 = !ERROR!
You can see that if the departure time is earlier the next day than the current time, we'll end up with incorrect data. The answer to this was quite simple - IF the departure hours are less (<) than current hour, we add 24 to it.
Code:
02.09
(02 + 24) * 60 = 1560
1560 + 09 = 1569
19.38
19 * 60 = 1140
1140 + 38 = 1178
1569 - 1178 = 391 mins
391 = 6 hours and 31 minutes
6 hours and 31 minutes from 19.38 is indeed 02.09
In practice, it was actually easier to deal with the subtraction of the hours and minutes separately and add them together after, but the principle remains the same.
The end result was having the number of minutes stored in %DEPTDCAL which could be used in the insert calendar entry action, along with %GCTIT (lol?) and %GCLOC.
* Check post 3 for current limitations with this task
GoogleMT
Minimalistic Text is a great application that can display any Tasker variable you send to it. The MT calendar widget backup is included in the .zip file. Once you have it on your home screen, you'll have to edit the font sizes etc to make this look good for you - it's currently fugly.
This task splits out some of the useless data such as the current year and passes the variables you would look to use over to MT.
Google-AutoNav
The profile is triggered by the context of a calendar event becoming active with matching matching variables %GCLOC & %GCTIT (lol?).
GCAutoNav
Finally, this task loads up the navigation at the equivalent of %DEPTD with the destination of %GCLOC. It sets %GCNAV to 1 to let Tasker know it can set another navigation entry should it wish on the next refresh...
And off you trot...
Google_calendar_mtpref
This should be dragged into the sdcard/MinimalisticTextPreferences folder. It can then be selected in the MT Preference Manager or by selecting the 'restore' option when creating a new MT widget.
Download | Change Log | FAQ
Limitations and Shortfalls
1) Have to split via the current month – Needs to be edited every month or use 12 IF variables.
2) Gets current location – may not be where you’re departing from! Need to look at including departure location in 'where' field.
3) A profile cannot currently be triggered by %VARIABLE = %TIME. Pleaded with Tasker Dev.
4) Incoming *meeting* SMS will overwrite the previous data & the widget details. Need some kind of loop to avoid overwriting.
5) Buffer time - didn't include the fact that you may want to leave 15 minutes or so spare...
6) MT widget only receives *meeting* entries. Need to get non-meeting entries into the calendar for a useful widget.
7) Time in seconds until the departure time does not consider days. Python script required to convert date from XML feed format:
'Wed Jun 1, 2011' to '5-30-11' (which is %DATE %TIME). Any volunteers?!
FAQ
Q) I just want to use the calendar widget only. Can I do that?
A) Yes, there's a separate download below.
Q) I have many other Tasker questions, can I post them here??
A) To avoid clutter, probably best to use this official Google group
Q) Where can I learn more about Tasker?
A) The manual and Profiles and step-throughs on the Tasker wiki and you’ll be up to speed in no time.
Change Log
V2
Code:
* Private XML calendar feed used, rather than SMS service.
* Full Google Calendar widget via Minimalistic Text
* Calendar provides default alarm 'buffer time' to navigation start.
* Renamed most tasks
* More intelligent tasks to handle multiple 'meeting' event.
* Prevented multiple navigation entries on refresh by using [B]%GCNAV[/B] set to 2.
V3 - Coming Soon!
Code:
* Profile triggered by [B]%VARIABLE[/B] = [B]%TIME[/B].
* Read departure location from calendar rather than assuming current location
* Python script to navigation events more than 24 hours away
Future Requests
None as yet.
Installation Instructions
Download and import the following 12 tasks:
GCAppLoc
GCAppDesc
GCAppTime
GCAppTit (lol?)
GCGetJD
GCJD
GCJT
GCAT
GCJTMaths
GCNavMaths
GCEntry
GCMT
Download and import the following 2 profiles:
Google-Calendar
Google-AutoNav
The .zip folder also contains the file Google_calendar_mtpref. This should be dragged into the sdcard/MinimalisticTextPreferences folder. It can then be selected in the MT Preference Manager or by selecting the 'restore' option when creating a new MT widget.
Credits: RichardKemp for prompting me to go RSS hunting.
------------------------------------------------------------------------------------------------------
The thanks meter lets me know I'm appreciated!
Wow!
You're on a roll!!!
Don't need this profile but I'll take a look for inspiration and new ideas.
Check it :-]
Archon810 said:
Check it :-]
Click to expand...
Click to collapse
Love the Skynet reference! Thank you
At 12:37am BST on May 24th 2011, Tasker became self aware....
leftAlone said:
You're on a roll!!!
Don't need this profile but I'll take a look for inspiration and new ideas.
Click to expand...
Click to collapse
Any testers and feedback appreciated!
Sweet, thanks for sharing, I will have a good hunt through this later when I have a moment.
I used to have something similar set up by using google apps script to make a publicly accessible spreadsheet containing my calendar entires, and download that spreadsheet (as a csv) using tasker. Unfortunately this stopped working when Google forced the use of https on all Docs, as neither Tasker nor any other way I could find to do it (I tried curl and wget) would allow https. Any suggestions for this? I would prefer not to use the sms version you mention so as not to clog up my inbox. Another way that almost works is getting the daily email agenda google offers, except Tasker can't access email bodies (only subjects, grr).
I was half considering writing some sort of app to make future calendar data accessible easily to tasker. I may do this over summer.
richardkemp said:
Sweet, thanks for sharing, I will have a good hunt through this later when I have a moment.
I used to have something similar set up by using google apps script to make a publicly accessible spreadsheet containing my calendar entires, and download that spreadsheet (as a csv) using tasker. Unfortunately this stopped working when Google forced the use of https on all Docs, as neither Tasker nor any other way I could find to do it (I tried curl and wget) would allow https. Any suggestions for this? I would prefer not to use the sms version you mention so as not to clog up my inbox. Another way that almost works is getting the daily email agenda google offers, except Tasker can't access email bodies (only subjects, grr).
Click to expand...
Click to collapse
I had a quick google on your suggestion and came up with a couple of applications here and here. You've also got me thinking that I must be able to pull a queried RSS feed from the calendar that would support the 'widgets' on the iGoogle home page for example. I'll dig a little further into this, as same with you, I failed when first looking at the 5am agenda email.
EDIT: Your prompting has lead me to this page which has resulted in me being able to get a private url of my agenda in xml or html output! Thank you! Looks like I have another evening of variable splits in front of me.....
I was half considering writing some sort of app to make future calendar data accessible easily to tasker. I may do this over summer.
Click to expand...
Click to collapse
I've heard a few people screaming out for task and agenda synchronisation from outlook without exchange server use. I don't know if someone has cracked this yet, but a CSV export would surely be pretty easy to convert?
This is cheeky, but any chance of getting this to work with TfL?
sabret00the said:
This is cheeky, but any chance of getting this to work with TfL?
Click to expand...
Click to collapse
Which aspect of it? Do you mean train times as opposed to by car?
Sent from my HTC Desire using XDA Premium App
Version 2 Up!
Change Log
V2
Code:
* Private XML calendar feed used, rather than SMS service.
* Full Google Calendar widget via Minimalistic Text
* Calendar provides default alarm 'buffer time' to navigation start.
* Renamed most tasks
* More intelligent tasks to handle multiple 'meeting' event.
* Prevented multiple navigation entries on refresh by using [B]%GCNAV[/B] set to 2.
V3 - Coming Soon!
Code:
* Profile triggered by [B]%VARIABLE[/B] = [B]%TIME[/B].
* Read departure location from calendar rather than assuming current location
* Python script to navigation events more than 24 hours away
FAQ
Q) I just want to use the calendar widget only. Can I do that?
A) Yes, there's a separate download link.
Let me know it works folks!
Glad to have helped in some small way! Also incredibly grateful you actually found a way to make this work, once my exams are over I'll get on it and adapt this to my needs
As a suggestion for further uses for this calendar data, what I use it for is automatically setting the time I need to wake in the mornings. Basically, when I go to sleep I run a task which dims the screen, quiets the phone, etc etc. It also sets my alarm time to 7 hours in the future, *or two hours before my first appointment of the day*, whichever is sooner. Currently this uses a series of alarm profiles/tasks in Tasker, but I switch to Gentle Alarm when Tasker support works.
Again, when exams are over I'll (possibly) write up my 'Alarm in Tasker' solution and post here, with comments on how to integrate with your calendar stuff.
richardkemp said:
Glad to have helped in some small way! Also incredibly grateful you actually found a way to make this work, once my exams are over I'll get on it and adapt this to my needs
As a suggestion for further uses for this calendar data, what I use it for is automatically setting the time I need to wake in the mornings. Basically, when I go to sleep I run a task which dims the screen, quiets the phone, etc etc. It also sets my alarm time to 7 hours in the future, *or two hours before my first appointment of the day*, whichever is sooner. Currently this uses a series of alarm profiles/tasks in Tasker, but I switch to Gentle Alarm when Tasker support works.
Again, when exams are over I'll (possibly) write up my 'Alarm in Tasker' solution and post here, with comments on how to integrate with your calendar stuff.
Click to expand...
Click to collapse
You certainly gave me a nudge in the right direction!
I'll look forward to your write up and interested to see how you get the alarm to trigger. Good luck in your exams!
Seems like the download for calendar only is 0 bytes. At least for me. I tried 5 times
Jufis said:
Seems like the download for calendar only is 0 bytes. At least for me. I tried 5 times
Click to expand...
Click to collapse
I've just tried and the file won't open for me either. Strange... Thanks for letting me know, I'll repost later when I have access to the files.
Sent from my HTC Desire using XDA Premium App
Jufis said:
Seems like the download for calendar only is 0 bytes. At least for me. I tried 5 times
Click to expand...
Click to collapse
Replaced the download - should work now. Thanks again for letting me know
The alarm trigger is a bit hackish.. basically there's two profiles, one runs each hour if the night variable is set, splits %TIME and checks if %TIME1 matches %ALARMHOUR. If so, it turns on another profile which runs every 5 mins, doing a similar thing to check if %TIME2 is greater than %ALARMMINUTES. If true, turn off profile and run the alarm task.
Prior to that version I was using another little trick Pent recommended me (not quite as good though), I had a profile with the context %TIME > %ALARMTIME, but obviously it didn't check the variables and didn't fire. TO solve this there was another profile which every 15 mins (when %NIGHT is set) would set %ALARMTIME to %ALARMTIME. Apparently re-setting the variable like that triggers the check. The first one I mentioned is a bit more efficient. I have considered switching to using calendar event based triggering, but it wasn't immediately obvious to me how I could edit the alarm event's time once set, short of literally editing the event on the calendar.
hi Brandall,
already read me elsewhere isn't it?
FAQ
Q) I just want to use the calendar widget only. Can I do that?
A) Yes, there's a separate download link.
Let me know it works folks!
Click to expand...
Click to collapse
so I can tell that it works about var and MT but... as i am franch speaking and so GC is french xml tags are to be corrected on splitting task ... where - event status and so one... CEST instead BST for continental (gmt+1)
Also as mentionned early in that thread should use some convenience fullfiling the appointment so could easly to get splitting process....
i'm actually on it .
I stay tuned as soon as it is corrected for french speaking I would give back report about mod I have done...
tks a lot very good way to learn how splitting process works
richardkemp said:
The alarm trigger is a bit hackish.. basically there's two profiles, one runs each hour if the night variable is set, splits %TIME and checks if %TIME1 matches %ALARMHOUR. If so, it turns on another profile which runs every 5 mins, doing a similar thing to check if %TIME2 is greater than %ALARMMINUTES. If true, turn off profile and run the alarm task.
Click to expand...
Click to collapse
Not too hackish! I like it... Hadn't thought of doing that - At worst it triggers the alarm a few minutes late, and doesn't use an additional calendar entry... I'm really hoping the next release will have the context %VAR = %TIME...
Prior to that version I was using another little trick Pent recommended me (not quite as good though), I had a profile with the context %TIME > %ALARMTIME, but obviously it didn't check the variables and didn't fire. TO solve this there was another profile which every 15 mins (when %NIGHT is set) would set %ALARMTIME to %ALARMTIME. Apparently re-setting the variable like that triggers the check. The first one I mentioned is a bit more efficient. I have considered switching to using calendar event based triggering, but it wasn't immediately obvious to me how I could edit the alarm event's time once set, short of literally editing the event on the calendar.
Click to expand...
Click to collapse
I prefer what you've done to using a calendar entry - It felt messy doing that, although I suppose it can have the appointment title, destination time etc etc in...

How to start a specific Spotify Playlist?

I need a way for Tasker to launch Spotify and start a specific playlist.
As far as I know, this can either be done with command line or launch Spotify with some parameters through Tasker.
How can this be done?
I found a somewhat helpful website: http://stackoverflow.com/questions/5252345/spotify-intent-in-android?rq=1
I have tried to understand the code and make a task i Tasker.
Action: android.intent.action_VIEW
Cat: default
Data: spotify:user:khaffnerlaylist:[long ID i found with logcat]
Target: Activity
The rest of the fields are blank.
It does not seem to do anything

[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?

Categories

Resources