I must've gone through ever Stack Overflow question based on the Google Calendar so far with no luck what so ever. I've been trying this for hours now and got little to no results at all.
I'm a pretty new programmer with Java and Android, with quite little experience out of the field as it is. Basically the main problem I am having is with viewing another user's Google Calendar which is set to public.
At the moment, from the Google tutorials and other sites I've managed to get the calendar showing, which is pretty simple enough. It'll just load up and show the current user's calendar. Which can literally be done with (with a simple button in the layout).
public void onClick(View view) {
// A date-time specified in milliseconds since the epoch.
long startMillis = System.currentTimeMillis();
Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
builder.appendPath("time");
ContentUris.appendId(builder, startMillis);
Intent intent = new Intent(Intent.ACTION_VIEW).setData(builder.build());
startActivity(intent);
}
Obviously this doesn't pass in any user data for the public account or anything, I've been reading through the Calendar Provider Developer guides within the Google tutorials. I've tried to set up the account details thing, but it just never works. I've tried to do it as a Sync Adapter, but honestly I just know I'm not doing it right. I don't know if I really even need to use a Sync Adapter as all I want to do is literally see the events, not modify anything or update anything.
I am using API 14+ and want to user the Calendar Provider etc. It looks simple enough but I've been bashing my head against this for a few days and put a lot of hours into it and seemingly nothing I do works. At least I've got some sort of calendar opening but it's not what I want.
Is it all just down to the sync adapter? If so how will I be able to call a calendar? Another question similar had
private static Uri buildCalUri() {
return CalendarContract.Calendars.CONTENT_URI
.buildUpon()
.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
.appendQueryParameter(Calendars.ACCOUNT_NAME, ACCOUNT_NAME)
.appendQueryParameter(Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL)
.build();
}
I'm hoping this is something similar to what I need but I'm very unsure. In the developer tutorial ACCOUNT_TYPE_LOCAL was important if the account wasn't on the device
Any help will be greatly appreciated!
If you are looking to integrate the public Google Calendar (www.google.com/calendar) with your Android Application, you have to use the Google Calendar API.
The easiest method would be download the Google Calendar Client Library from here and then use the API Reference here. In the Client Library Page, you want to download "Google APIs Client Library for Java (rc)" package to integrate into your Android App.
You will first need to go to API Console to create an App with Calendar API Access .
If you do not want to use the native library, you can even do it using REST API (use HTTP GET & POST Commands), example App here
Hope this helps.
For anybody that has followed the Android Developer API example, but still can't find how to add a public calendar. Try out
CalendarListEntry gracieCal = new CalendarListEntry();
gracieCal.setId("your-public-calendar-id");
mService.calendarList().insert(gracieCal);
Events events = mService.events().list(gracieCal.getId())
.setMaxResults(10)
.setTimeMin(new DateTime(System.currentTimeMillis()))
.setOrderBy("startTime")
.setSingleEvents(true)
.execute();
List<Event> items = events.getItems();
'mService' is the com.google.api.services.calendar.Calendar instance that you should have already created. (see the api tutorials mentioned by the other answer)
'your-public-calendar-id' can be found in the settings for your public google calendar.
I'm using intent to create a new event in google calendar application.
However i don't find a way to add a photo as an attachment.
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra(Events.TITLE, "Learn Android");
intent.putExtra(Events.EVENT_LOCATION, "Home sweet home");
intent.putExtra(Events.DESCRIPTION, mImageUri);
intent.putExtra(Events.A, mImageUri); ===> ?
How do i do this?
I think that it unfortunately isn't supported by API but I could be wrong. Here is full event table and there is nothing about attachments.
EDIT :
This feature is still a lab, and Google for now won't expose it via the API. See the source.
I am building an app for the android, i dont need my app to have a calendar be part of it(plus it would defeat the purpose), my app allows the user to listen to a radio station, and needs the option to set an event to(remember to listen to the radio at a specific time), if the app has its own calendar then the event alarms will only go off if the user has the app open... pointless. i have been looking and cannot find, is there a way to use an intent or something else to open a google calendar or some other calendar that Android might have?
i need to put my intent(/ other code) in my listener which i already have and looks like this for now
private View.OnClickListener reminder = new View.OnClickListener() {
#Override
public void onClick(View v) {
// open calendar code goes here.
}
};
i dont need the app to pre-fill in any field in the calendar just open it, i will leave the rest up to the user.
all help is welcome and thank you
If you just want to open the calendar you can use and intent with EITHER of these component names (you might have to cater for both if you want to support older phones)
Intent i = new Intent();
//Froyo or greater (mind you I just tested this on CM7 and the less than froyo one worked so it depends on the phone...)
cn = new ComponentName("com.google.android.calendar", "com.android.calendar.LaunchActivity");
//less than Froyo
cn = new ComponentName("com.android.calendar", "com.android.calendar.LaunchActivity");
i.setComponent(cn);
startActivity(i);
If you want to go to the add event screen (which sounds better for your purpose) use something like:
//all version of android
Intent i = new Intent();
// mimeType will popup the chooser any for any implementing application (e.g. the built in calendar or applications such as "Business calendar"
i.setType("vnd.android.cursor.item/event");
// the time the event should start in millis. This example uses now as the start time and ends in 1 hour
i.putExtra("beginTime", new Date().getTime());
i.putExtra("endTime", new Date().getTime() + DateUtils.HOUR_IN_MILLIS);
// the action
i.setAction(Intent.ACTION_EDIT);
startActivity(i);
(code is untested, copied from an existing project)
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.
I'm planning on doing a application for Android 2.1 that changes song every minute (through what I hope exists in Android, "next") for the application using the audio device atm.
So if I have Spotify running in background already, playing music, can I through my program change to the next track?
Let me know if I was unclear about anything.
Thanks in advance!
I know this is a bit old question, but it took me some time searching something other then what is mentioned here.
There is a workaround - broadcasting media button action. There is one catch - receiver can recognize if the broadcast was from system or from another app, so they can ignore the non-system broadcasts.
Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
synchronized (this) {
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
}
There's no universal audio transport API for music applications, so you'd need to see if the music applications you're targeting publicly expose service bindings or intents. If not, you won't be able to do this.
Just posted a relevant answer here
Using the AudioManager's dispatchMediaKeyEvent() method with a defined KeyEvent worked for me using the latest SDK.
The system music homescreen widget sends this intent for the built-in music player:
final ComponentName serviceName = new ComponentName(context,
MediaPlaybackService.class);
intent = new Intent(MediaPlaybackService.NEXT_ACTION);
intent.setComponent(serviceName);
pendingIntent = PendingIntent.getService(context,
0 /* no requestCode */, intent, 0 /* no flags */);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
But it looks like this might take some hackery to implement outside packages in the music app itself because the MediaPlaybackService only accepts explicit Intents and isn't accessible from the outside. This thread seems to indicate it's possible with a bit of hackery, though.
But even then, as Roman said, not every music player will respect that Intent. You'll have to check with Spotify/Pandora/Last.fm themselves and see if they have any available intents to bind like that.
Looks that it's possible to use AudioManager to inject media keys.
Here is a snippet from another question
this.mAudioManager = (AudioManager) this.context.getSystemService(Context.AUDIO_SERVICE);
long eventtime = SystemClock.uptimeMillis();
KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0);
mAudioManager.dispatchMediaKeyEvent(downEvent);
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0);
mAudioManager.dispatchMediaKeyEvent(upEvent);
The same way you can inject PlayPause button and some others.
I've tested it within a background service controlling Youtube and it worked for Android 6