Creating a Custom Expanded View in Code - java

I want to customize the notification area, adding an icon to the right and few buttons.
I've read the tutorial here: http://developer.android.com/guide/topics/ui/notifiers/notifications.html
The problem is that I need to include this code in a library, an SDK that I want to distribute to improve notifications. (See http://hub.buzzbox.com/)
Is it possible to write all the UI in code, without the need of the xml to describe the remote view? This is because resources cannot be included in an SDK, so I would need to ask the users of my SDK to add an xml to their resources and to reference all the resources by name... which I would like to avoid.
I've already written other parts of the SDK user interface completely in Java code but I'm having issues to do the same for the Remove View.
A RemoteView is usually created like this:
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
Can I create a RemoteView from I layout that I create with Java code?
Any other solutions?

I thought that you might be able to do this with your own Parcel, but looking at the code, the Parcel simply stores the package name and layout (resource) id, as used by the main constructor.
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackage);
dest.writeInt(mLayoutId);
int count;
if (mActions != null) {
count = mActions.size();
} else {
count = 0;
}
dest.writeInt(count);
for (int i=0; i<count; i++) {
Action a = mActions.get(i);
a.writeToParcel(dest, 0);
}
}
I can't see a way of doing this and think it may not be possible.

Related

Get slidingpanellayout events

I'm using sliding panels with my android app, but i need to get an event when the panel is up, is there a way listen to when it happens?
im using a sothree Sliding panel library
Looks like you are talking about umano/AndroidSlidingUpPanel. After briefly looking at the documentation/code you should be able to set a PanelSlideListener to your SlidingUpPanelLayout. They also provide a SimplePanelSlideListener which inserts no-ops for any functions you choose not to implement, which is probably what you will want to use.
For example inside of your Activity's onCreate you could do something like:
SlidingUpPanelLayout slidingPanel = (SlidingUpPanelLayout)findViewById(R.id.your_sliding_layout);
slidingPanel.setPanelSlideListener(new SimplePanelSlideListener() {
#Override
public void onPanelExpanded(View panel) {
// Insert your code here
}
});

getSerializable returns different types depending on how app exited

I need to save an int[][] into a Bundle so it could be saved during onSaveInstanceState() and restored on onCreate(). First, I've decided to make it straightforward and flatten a 2D array into 1D and deflatten on load. It all worked fine.
I've decided to find an easier way. I was told that 2D arrays are serializable, so I made it something like this:
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putSerializable("CELLS_STATE",universe.getUniverse());
super.onSaveInstanceState(savedInstanceState);
}//onSaveInstanceState
where universe.getUniverse() returns an int[][].
Reloading within onCreate():
if(savedInstanceState != null)
{//save data exists, reload it
universe = new Universe( (int[][])savedInstanceState.getSerializable("CELLS_STATE") );
}
Here's the catch. If I run the program and turn my phone so the screen changes orientation, it loads perfectly fine.
But, when I press the home button and then kill the app using an app killer (in my case it is Battery Doctor) and try to start it again from the menu, it crashes and I can launch it only from the second attempt, and the saved state is lost. The error that is given on that crash points to the line with getSerializable I've specified above, and it is:
java.lang.ClassCastException: java.lang.Object[] cannot be cast to int[][]
This confuses me. So, whenever screen orientation changes (and maybe something else), getSerializable returns something that can be cast to a 2D array (probably, Serializable). But whenever the app is killed, it returns something that cannot be cast. What causes such a strange behaviour and is there a way to bypass it?
What causes such a strange behavior...?
It appears that this is a bug in the Parcel's implementation, I recommend to read comment #6 which contains the very good explanation of bug's nature.
.. and is there a way to bypass it?
The following code should work:
if (savedInstanceState != null) {
final Object[] objects = savedInstanceState.getSerializable("CELLS_STATE");
final int[][] cells = new int[objects.length][];
for (int i = 0; i < objects.length; i++) {
cells[i] = (int[]) objects[i];
}
universe = new Universe(cells);
}

how to add like button with a counter to my android app

I have wondered the facebook developers docs,
but saw only how to add "like action" and "likes counter" to html page.
I mean for the like counter saved in fb servers for that page.
How is it done in java for an android app?
In Xml layout in which u have button, in button attribute add
android:onclick="like_counter";// this will call that method
in activity,
globally code this
int counter=0;
public int like_counter()
{
counter++;
return counter;
}
hope this is what u r asking...

app crashes when adding OnItemSelectedListener

I recently made an update to the iOS version of an app I made and I want to put that same functionality into the Android version. Basically, it takes user input of a year, which they select from a list and then the year previous to that is entered into the placeholder text of text field I specify. When I looked up how to do the same functionality in Android, I found out I needed an OnItemSelectedListener. However, that is when trouble arises. After adding the necessary code, and importing AdapterView into my Activity, my app keeps crashing on first launch. Since I am not sure where it keeps crashing, here is a link to my app's github page
Github Experimental branch
The code on the master branch works fine, so this is really strange.
Since the files are hard to decipher, here is the code I used to apply the OnItemSelectedListener:
// give Spinner a listener for new functionality to work
selection.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parentView,
View selectedItemView, int position, long id) {
// get year selection for use with new functionality
int iyear = Integer.parseInt(selection.getSelectedItem().toString());
balance.setHint(R.string.balance + " from 12/31/" + pyear.getPrevYear(iyear));
}
// create empty method
public void onNothingSelected(AdapterView<?> parentView) {}
});
Make sure the var balance is not null at the time of setHint. It could be that the id in findViewById is not right.
Make sure that R.id.amount is a view inside of R.layout.main.
I still don't see the LogCat which is the most vital piece of information when tracking down an error...
So these are my guesses:
I don't see where you define an adapter for selection so I assume that you do this in the XML. Have you confirmed that selection.getSelectedItem().toString() is a valid String for Integer.parseInt()?
If you have access to the array (call it selectionArray) you can simply use:
... + pyear.getPrevYear(selectionArray[position]);
R.string.balance is an integer that references the String that you want. To display the String itself you want to use getString(R.string.balance) or probably getResources().getString(R.string.balance).
Verify none of your variables are null: selection, balance, and pyear.
To explain the first point a little more:
Create a class variable for the array and the String:
int[] choicesArray;
Initialize it in onCreate();
choicesArray = getResources().getIntArray(R.array.choices_array);
In OnItemSelectedListener use:
balance.setHint(getResources().getString(R.string.balance) + " from 12/31/" + (choicesArray[position] - 1));
I went through and copied things from the master branch and things started working without crashing. Now, I am having issues with the hint, but since this question on why it kept crashing, I am not sure I can keep the question open.

How to support multiple android version in your code?

Take accessing contacts in android
android.jar for versions 1.6 has People.CONTENT_URI for invoking contacts related info whereas in later versions we need to have api support for RawContacts.CONTENT_URI.
Same thing is true for accessing calendar for instance as its URI is changed in android 2.2.
Is there a best practice to manage all different changes without adding additional application or build separately for each version of changes?
For my money, a very good answer is at http://android-developers.blogspot.co.uk/2010/07/how-to-have-your-cupcake-and-eat-it-too.html. However, the example there is a little more complicated than need be, so based on that, here is an example of how to cope with it when building notifications. The underlying reason this works is a consequence of how java engines interpret classes: it only looks at them when needed, so if you wrap version specific code up in a class and only create it when you know you are using that version, it all works ...
There are, as far as I can tell, two generations of approaches to creating notification, and a naming change along the way in the second. So that gives three ways to do it. For each way, create a class with the notification generation in it:
The first approach (used through to Gingerbread):
public class MyNotificationBuilderToGingerBread {
Notification notification = null;
MyNotificationBuilderToGingerBread(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, int flags) {
notification = new Notification(R.drawable.ic_sb, ticker, timeStamp);
notification.setLatestEventInfo(myContext, title, info, pendingIntent);
notification.flags |= flags;
}
Notification get() {
return notification;
}
}
The second approach, Honeycomb to IceCreamSandwich:
public class MyNotificationBuilderHoneyCombToIceCreamSandwich {
Notification.Builder mb = null;
MyNotificationBuilderHoneyCombToIceCreamSandwich(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
mb = new Notification.Builder(myContext);
mb.setSmallIcon(icon);
mb.setContentIntent(pendingIntent);
mb.setContentTitle(title);
mb.setContentText(info);
mb.setWhen(timeStamp);
if (ticker != null) mb.setTicker(ticker);
mb.setOngoing(onGoing);
}
Notification get() {
return mb.getNotification();
}
}
The second generation, with the name change, Jellybean (onwards, so far ...):
public class MyNotificationBuilderJellyBean {
Notification.Builder mb = null;
MyNotificationBuilderJellyBean(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
mb = new Notification.Builder(myContext);
mb.setSmallIcon(icon);
mb.setContentIntent(pendingIntent);
mb.setContentTitle(title);
mb.setContentText(info);
mb.setWhen(timeStamp);
if (ticker != null) mb.setTicker(ticker);
mb.setOngoing(onGoing);
}
Notification get() {
return mb.build();
}
}
Then, you just need to pick which class to instantiate on the fly:
// System information
private final int sdkVersion = Build.VERSION.SDK_INT;
// If you want to go really old:
// (actually, there is a question about how this issue should be handled
// systematically. Suggestions welcome.)
// final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
// This is for a permanent notification. Change the final argument (flags or boolean) if it isn't meant ot be
// For meaning of other variable, see notification documentation on the android website.
if (sdkVersion < Build.VERSION_CODES.HONEYCOMB) {
MyNotificationBuilderToGingerBread mnb = new MyNotificationBuilderToGingerBread(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR);
notification = mnb.get();
}
else if (sdkVersion < Build.VERSION_CODES.JELLY_BEAN) {
MyNotificationBuilderHoneyCombToIceCreamSandwich mnb = new MyNotificationBuilderHoneyCombToIceCreamSandwich(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
notification = mnb.get();
}
else {
MyNotificationBuilderJellyBean mnb = new MyNotificationBuilderJellyBean(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
notification = mnb.get();
}
// Send the notification.
notificationManager.notify(idForNotificationManager, notification);
Hope this helps!
There are many resources for you to utilize to help support multiple versions of android.
Read this blog post here and
then read this one here, they
will help you address API level
version support issues.
Read this blog post on multiple
screen support, especially how the
asset hierarchy in parsed in res
folder. This will help you
understand and design how to do
asset folder structure to support
different screen size/densities and
android versions.
Lastly write your own custom ant build
scripts so that you can compile with
all versions of android.
Quite Honestly, it's a pain.
I usually, just isolate parts of code that are different and access them using abstract classes. So technically creating different version for different OS.
But there are other ways. The best one i've seen involves using reflection.
If you don't really need the new functionnalities, and really have to support old Android versions, drop it. Build your app for the oldest version, and don't bother with this kind of thing.
In the other case, you can detect the version using Build, and use reflection to load the classes you need. An example of that can be found in the source code of the K9Mail app
There's a nice article on android.com about it:
http://developer.android.com/resources/articles/backward-compatibility.html
Personally I would suggest the wrapper class or wrapper library solution. But in small cases the reflection should be fine (and in case performance is not a problem for you).
If you need more info, ask in comments.
This is a great article for when you have to do reflection in Android (to support multiple API levels).
And when you have to have different resources for different API Levels, this is the reference to use (see the section on "Platform Version (API level)").
If on Eclipse, from ADT version 17 you can specify code to run with some version simply as described in Lint API Check.
The code word is #TargetAPI(XX)
Hope it helps
Best practice (though not for Android, but for J2ME) to my knowledge is to use preprocessing C/C++ styled statements, like:
//#if S40
...
//#else
...
//#endif
Some IDE's support these kind of preprocessing, e.g. Netbeans. To my knowledge Eclipse has some plugins to enable preprocessing also. I don't really know are they applicable to Android development. Try to google yourself.

Categories