From 8dd1738354dbae311cf77342dae5c4f9c7f14adb Mon Sep 17 00:00:00 2001
From: Mike C
+ * This class cannot be instantiated.
+ */
+public final class BreadCrumber {
+ /**
+ * Static helper method to generate bread crumbs. Bread crumb strings will
+ * be properly formatted for the current language, including right-to-left
+ * languages, as long as the proper
+ * {@link com.twofortyfouram.locale.platform.R.string#twofortyfouram_locale_breadcrumb_format}
+ * string resources have been created.
+ *
+ * @param context
+ * {@code Context} for loading platform resources. Cannot be
+ * null.
+ * @param intent
+ * {@code Intent} to extract the bread crumb from.
+ * @param currentCrumb
+ * The last element of the bread crumb path.
+ * @return {@code String} presentation of the bread crumb. If the intent
+ * parameter is null, then this method returns currentCrumb. If
+ * currentCrumb is null, then this method returns the empty string
+ * "". If intent contains a private Serializable instances as an
+ * extra, then this method returns the empty string "".
+ * @throws IllegalArgumentException
+ * if {@code context} is null.
+ */
+ public static CharSequence generateBreadcrumb(final Context context,
+ final Intent intent, final String currentCrumb) {
+ if (null == context) {
+ throw new IllegalArgumentException("context cannot be null"); //$NON-NLS-1$
+ }
+
+ try {
+ if (null == currentCrumb) {
+ Log.w(Constants.LOG_TAG, "currentCrumb cannot be null"); //$NON-NLS-1$
+ return ""; //$NON-NLS-1$
+ }
+ if (null == intent) {
+ Log.w(Constants.LOG_TAG, "intent cannot be null"); //$NON-NLS-1$
+ return currentCrumb;
+ }
+
+ /*
+ * Note: this is vulnerable to a private serializable attack, but
+ * the try-catch will solve that.
+ */
+ final String breadcrumbString = intent
+ .getStringExtra(com.twofortyfouram.locale.Intent.EXTRA_STRING_BREADCRUMB);
+ if (null != breadcrumbString) {
+ return context
+ .getString(
+ R.string.twofortyfouram_locale_breadcrumb_format,
+ breadcrumbString,
+ context.getString(R.string.twofortyfouram_locale_breadcrumb_separator),
+ currentCrumb);
+ }
+ return currentCrumb;
+ } catch (final Exception e) {
+ Log.e(Constants.LOG_TAG,
+ "Encountered error generating breadcrumb", e); //$NON-NLS-1$
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Private constructor prevents instantiation.
+ *
+ * @throws UnsupportedOperationException
+ * because this class cannot be instantiated.
+ */
+ private BreadCrumber() {
+ throw new UnsupportedOperationException(
+ "This class is non-instantiable"); //$NON-NLS-1$
+ }
+}
\ No newline at end of file
diff --git a/src/com/twofortyfouram/locale/Constants.java b/src/com/twofortyfouram/locale/Constants.java
new file mode 100644
index 0000000..7e22c51
--- /dev/null
+++ b/src/com/twofortyfouram/locale/Constants.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2013 two forty four a.m. LLC
+ * If a condition returns UNKNOWN, then Locale will use the last known return value on a best-effort
+ * basis. Best-effort means that Locale may not persist known values forever (e.g. last known values could
+ * hypothetically be cleared after a device reboot or a restart of the Locale process. If
+ * there is no last known return value, then unknown is treated as not satisfied (false).
+ *
+ * The purpose of an UNKNOWN result is to allow a plug-in condition more than 10 seconds to process a
+ * requery. A {@code BroadcastReceiver} must return within 10 seconds, otherwise it will be killed by
+ * Android. A plug-in that needs more than 10 seconds might initially return
+ * {@link #RESULT_CONDITION_UNKNOWN}, subsequently request a requery, and then return either
+ * {@link #RESULT_CONDITION_SATISFIED} or {@link #RESULT_CONDITION_UNSATISFIED}.
+ *
+ * @see Intent#ACTION_QUERY_CONDITION
+ */
+ public static final int RESULT_CONDITION_UNKNOWN = 18;
+
+ /**
+ * {@code Intent} action {@code String} broadcast by Locale to create or edit a plug-in setting. When
+ * Locale broadcasts this {@code Intent}, it will be sent directly to the package and class of the
+ * plug-in's {@code Activity}. The {@code Intent} may contain a {@link #EXTRA_BUNDLE} that was previously
+ * set by the {@code Activity} result of {@link #ACTION_EDIT_SETTING}.
+ *
+ * There SHOULD be only one {@code Activity} per APK that implements this {@code Intent}. If a single APK
+ * wishes to export multiple plug-ins, it MAY implement multiple Activity instances that implement this
+ * {@code Intent}, however there must only be a single {@link #ACTION_FIRE_SETTING} receiver. In this
+ * scenario, it is the responsibility of the Activities to store enough data in {@link #EXTRA_BUNDLE} to
+ * allow this receiver to disambiguate which "plug-in" is being fired. To avoid user confusion, it is
+ * recommended that only a single plug-in be implemented per APK.
+ *
+ * @see Intent#EXTRA_BUNDLE
+ * @see Intent#EXTRA_STRING_BREADCRUMB
+ */
+ public static final String ACTION_EDIT_SETTING = "com.twofortyfouram.locale.intent.action.EDIT_SETTING"; //$NON-NLS-1$
+
+ /**
+ * {@code Intent} action {@code String} broadcast by Locale to fire a plug-in setting. When Locale
+ * broadcasts this {@code Intent}, it will be sent directly to the package and class of the plug-in's
+ * {@code BroadcastReceiver}. The {@code Intent} will contain a {@link #EXTRA_BUNDLE} that was previously
+ * set by the {@code Activity} result of {@link #ACTION_EDIT_SETTING}.
+ *
+ * There MUST be only one {@code BroadcastReceiver} per APK that implements this {@code Intent}.
+ *
+ * @see Intent#EXTRA_BUNDLE
+ */
+ public static final String ACTION_FIRE_SETTING = "com.twofortyfouram.locale.intent.action.FIRE_SETTING"; //$NON-NLS-1$
+
+ /**
+ * {@code Intent} action {@code String} broadcast by Locale to create or edit a plug-in condition. When
+ * Locale broadcasts this {@code Intent}, it will be sent directly to the package and class of the
+ * plug-in's {@code Activity}. The {@code Intent} may contain a store-and-forward {@link #EXTRA_BUNDLE}
+ * that was previously set by the {@code Activity} result of {@link #ACTION_EDIT_CONDITION}.
+ *
+ * There SHOULD be only one {@code Activity} per APK that implements this {@code Intent}. If a single APK
+ * wishes to export multiple plug-ins, it MAY implement multiple Activity instances that implement this
+ * {@code Intent}, however there must only be a single {@link #ACTION_QUERY_CONDITION} receiver. In this
+ * scenario, it is the responsibility of the Activities to store enough data in {@link #EXTRA_BUNDLE} to
+ * allow this receiver to disambiguate which "plug-in" is being queried. To avoid user confusion, it is
+ * recommended that only a single plug-in be implemented per APK.
+ *
+ * @see Intent#EXTRA_BUNDLE
+ * @see Intent#EXTRA_STRING_BREADCRUMB
+ */
+ public static final String ACTION_EDIT_CONDITION = "com.twofortyfouram.locale.intent.action.EDIT_CONDITION"; //$NON-NLS-1$
+
+ /**
+ * Ordered {@code Intent} action {@code String} broadcast by Locale to query a plug-in condition. When
+ * Locale broadcasts this {@code Intent}, it will be sent directly to the package and class of the
+ * plug-in's {@code BroadcastReceiver}. The {@code Intent} will contain a {@link #EXTRA_BUNDLE} that was
+ * previously set by the {@code Activity} result of {@link #ACTION_EDIT_CONDITION}.
+ *
+ * Since this is an ordered broadcast, the receiver is expected to set an appropriate result code from
+ * {@link #RESULT_CONDITION_SATISFIED}, {@link #RESULT_CONDITION_UNSATISFIED}, and
+ * {@link #RESULT_CONDITION_UNKNOWN}.
+ *
+ * There MUST be only one {@code BroadcastReceiver} per APK that implements this {@code Intent}.
+ *
+ * @see Intent#EXTRA_BUNDLE
+ * @see Intent#RESULT_CONDITION_SATISFIED
+ * @see Intent#RESULT_CONDITION_UNSATISFIED
+ * @see Intent#RESULT_CONDITION_UNKNOWN
+ */
+ public static final String ACTION_QUERY_CONDITION = "com.twofortyfouram.locale.intent.action.QUERY_CONDITION"; //$NON-NLS-1$
+
+ /**
+ * {@code Intent} action {@code String} to notify Locale that a plug-in condition is requesting that
+ * Locale query it via {@link #ACTION_QUERY_CONDITION}. This merely serves as a hint to Locale that a
+ * condition wants to be queried. There is no guarantee as to when or if the plug-in will be queried after
+ * this {@code Intent} is broadcast. If Locale does not respond to the plug-in condition after a
+ * {@link #ACTION_REQUEST_QUERY} Intent is sent, the plug-in SHOULD shut itself down and stop requesting
+ * requeries. A lack of response from Locale indicates that Locale is not currently interested in this
+ * plug-in. When Locale becomes interested in the plug-in again, Locale will send
+ * {@link #ACTION_QUERY_CONDITION}.
+ *
+ * The extra {@link #EXTRA_ACTIVITY} MUST be included, otherwise Locale will ignore this {@code Intent}.
+ *
+ * Plug-in conditions SHOULD NOT use this unless there is some sort of asynchronous event that has
+ * occurred, such as a broadcast {@code Intent} being received by the plug-in. Plug-ins SHOULD NOT
+ * periodically request a requery as a way of implementing polling behavior.
+ *
+ * @see Intent#EXTRA_ACTIVITY
+ */
+ public static final String ACTION_REQUEST_QUERY = "com.twofortyfouram.locale.intent.action.REQUEST_QUERY"; //$NON-NLS-1$
+
+ /**
+ * Type: {@code String}.
+ *
+ * Maps to a {@code String} that represents the {@code Activity} bread crumb path.
+ *
+ * @see BreadCrumber
+ */
+ public static final String EXTRA_STRING_BREADCRUMB = "com.twofortyfouram.locale.intent.extra.BREADCRUMB"; //$NON-NLS-1$
+
+ /**
+ * Type: {@code String}.
+ *
+ * Maps to a {@code String} that represents a blurb. This is returned as an {@code Activity} result extra
+ * from {@link #ACTION_EDIT_CONDITION} or {@link #ACTION_EDIT_SETTING}.
+ *
+ * The blurb is a concise description displayed to the user of what the plug-in is configured to do.
+ */
+ public static final String EXTRA_STRING_BLURB = "com.twofortyfouram.locale.intent.extra.BLURB"; //$NON-NLS-1$
+
+ /**
+ * Type: {@code Bundle}.
+ *
+ * Maps to a {@code Bundle} that contains all of a plug-in's extras.
+ *
+ * Plug-ins MUST NOT store {@link Parcelable} objects in this {@code Bundle}, because {@code Parcelable}
+ * is not a long-term storage format. Also, plug-ins MUST NOT store any serializable object that is not
+ * exposed by the Android SDK.
+ *
+ * The maximum size of a Bundle that can be sent across process boundaries is on the order of 500
+ * kilobytes (base-10), while Locale further limits plug-in Bundles to about 100 kilobytes (base-10).
+ * Although the maximum size is about 100 kilobytes, plug-ins SHOULD keep Bundles much smaller for
+ * performance and memory usage reasons.
+ */
+ public static final String EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"; //$NON-NLS-1$
+
+ /**
+ * Type: {@code String}.
+ *
+ * Maps to a {@code String} that represents the name of a plug-in's {@code Activity}.
+ *
+ * @see Intent#ACTION_REQUEST_QUERY
+ */
+ public static final String EXTRA_ACTIVITY = "com.twofortyfouram.locale.intent.extra.ACTIVITY"; //$NON-NLS-1$
+}
\ No newline at end of file
From a2ded360a711f336cb82a7bbdfac4113cbf1e594 Mon Sep 17 00:00:00 2001
From: Mike C
+ * Some of our Smart accessories will support the Control API.
+ * The Control API enables the Extension to take total control of the accessory.
+ * It takes control over the display, LEDs, vibrator, input events.
+ * Because of this, only one Extension can run in this mode at a time.
+ * Topics covered here:
+ *
+ * Before a Control Extension can use an accessory, it must use the registration API
+ * content provider to insert a record in the extension table. It must also register
+ * information in the registration table. This must be done for each Host Application
+ * that the Extension wants to interact with.
+ *
+ * In order to find out what Host Applications are available and what capabilities they
+ * support, the Extension should use the Capability API.
+ *
+ * After a successful registration the Extension can start communicating with the Host
+ * Application. Since an Extension implementing this API takes complete control over the
+ * accessory only one Extension can run at a time.
+ *
+ * An Extension cannot just start executing whenever it wants, it needs to make sure that
+ * no other Extension is running, therefore the Extension can only request to be started,
+ * {@link Intents#CONTROL_START_REQUEST_INTENT}. When the Host Application is ready to give
+ * control to the Extension it will send a {@link Intents#CONTROL_START_INTENT}, see figure
+ * below.
+ *
+ *
+ * When the Extension requests to start controlling the accessory the Host Application can
+ * either accept the request and give control to the Extension, or if something is not right
+ * the Host Application can send a {@link Intents#CONTROL_ERROR_INTENT}. See
+ * {@link Intents#EXTRA_ERROR_CODE} for different error codes that the Host Application can send.
+ *
+ * The {@link Intents#CONTROL_RESUME_INTENT} is sent when the Extension is visible on the accessory.
+ * From this point on the Extension controls everything, the Host Application just forwards the
+ * information between the accessory and the Extension.
+ *
+ * An Extension can also be paused, either if a high priority Extension needs to run for a
+ * while or if the Host Application is in charge of the display state and the display is
+ * turned off. In this case the Host Application sends a {@link Intents#CONTROL_PAUSE_INTENT}
+ * to the Extension. This means that there is no point for the Extension to update the display
+ * since it is either turned off or someone else has control over it. If the Extension would
+ * break this rule and try to update the display anyway, the Host Application will ignore these
+ * calls.
+ *
+ * When the Extension is in a paused state it no longer has control over the display/LEDs/
+ * vibrator/key events. As an example one could say that a telephony Extension has high priority.
+ * E.g. when a random Extension is running and the user receives a phone call. We want to pause
+ * the running Extension and let the telephony Extension display the caller id on the accessory
+ * display. When the phone call ends the telephony Extension is done and the other Extension can
+ * resume its running, it will then receive a {@link Intents#CONTROL_RESUME_INTENT}.
+ *
+ * When the {@link Intents#CONTROL_RESUME_INTENT} is sent from a Host Application the Extension is
+ * once again in charge of everything.
+ *
+ * When the user chooses to exit the Extension the Host Application will send a
+ * {@link Intents#CONTROL_PAUSE_INTENT} followed by a {@link Intents#CONTROL_STOP_INTENT}.
+ * From this point on the Host Application regains control.
+ *
+ * If the Extension would like to stop itself when running, like the telephony Extension, it can
+ * send a {@link Intents#CONTROL_STOP_REQUEST_INTENT} to the Host Application. The Host Application
+ * will then make sure to stop it and send a {@link Intents#CONTROL_STOP_INTENT}.
+ * If the extension was not already paused the it will be paused before it is stopped and a
+ * {@link Intents#CONTROL_PAUSE_INTENT} is sent before the {@link Intents#CONTROL_STOP_INTENT}.
+ * In case another Extension has been paused it will be resumed.
+ *
+ * Extensions implementing this API have the possibility to control the state of the accessory
+ * display.The display can be controlled via {@link Intents#CONTROL_SET_SCREEN_STATE_INTENT}.
+ *
+ * It is important that you program your Extension so that it consumes as little power as possible,
+ * both on the phone side and on the accessory. The accessory has a much smaller battery then the
+ * phone so use this functionality with caution. When possible, let the Host Application take control
+ * of the display state. That way you don't have to bother about the power consumption on the accessory.
+ * You can do this by setting the display state to "Auto".
+ *
+ * By default when your Extension starts the display state will be set to "Auto", which means that the
+ * Host Application controls the on/off/dim behavior. If the Extension wants to control the display state
+ * it must explicitly change the state.
+ *
+ * If the Extension controls the display state and you get a {@link Intents#CONTROL_STOP_INTENT}, meaning
+ * your Extension is no longer running, the Host Application will automatically take over the display
+ * control.
+ *
+ * Note that when in "Auto" mode, the Extension will receive a {@link Intents#CONTROL_PAUSE_INTENT} when
+ * display is off and a {@link Intents#CONTROL_RESUME_INTENT} when the display goes back on.
+ *
+ * Some accessories may support an additional display mode where information can be shown to the
+ * user while keeping the battery consumption to a minimum. In this active power save mode the
+ * display only supports monochrome (black and white) display content.
+ * Accessories with support for active power save mode indicates this in
+ * {@link Registration.DisplayColumns#SUPPORTS_LOW_POWER_MODE}.
+ * If the control extension wants use the active power save mode it must set the
+ * {@link Registration.ApiRegistration#LOW_POWER_SUPPORT} to TRUE when registering with a Host
+ * Application.
+ *
+ * If both the extension and the accessory support active power save mode, this mode will be
+ * activated when the screen would otherwise go off.
+ * This means that if screen state is {@link Intents#SCREEN_STATE_AUTO} the accessory will decide when to
+ * enter active power save mode.
+ * If screen state is {@link Intents#SCREEN_STATE_ON} or {@link Intents#SCREEN_STATE_DIM} the
+ * extension can put the display in active power save mode by setting the screen state to
+ * {@link Intents#SCREEN_STATE_OFF}.
+ * The {@link Intents#CONTROL_ACTIVE_POWER_SAVE_MODE_STATUS_CHANGED_INTENT} intent is sent to the
+ * extension when the display enters active power save mode both when the active power save
+ * mode is initiated by the accessory and extension.
+ * When in active power save mode the extension is expected to provide monochrome display
+ * content through the same intents as in normal display mode.
+ * The extension can update the display in the same ways as in normal display mode.
+ *
+ * If the screen state is {@link Intents#SCREEN_STATE_AUTO} and the display was put in active
+ * power save mode by the accessory, the accessory also decides when to leave the active
+ * power save mode.
+ * In this mode the extension will not receive any input events from the accessory as these
+ * will cause the display to leave the active power save mode.
+ * If the display was put in active power save mode by the control extension it is the
+ * responsibility of the control extension to decide when to leave the active power save mode
+ * by setting the screen state to {@link Intents#SCREEN_STATE_ON}.
+ * If the extension wants to get input events when the screen is in active power save mode, it must
+ * manually put the display in active power save mode.
+ * When the display leaves the active power save mode a
+ * {@link Intents#CONTROL_ACTIVE_POWER_SAVE_MODE_STATUS_CHANGED_INTENT} will always be sent to
+ * the extension and the extension is expected by update the display with new content.
+ *
+ * The accessory might have one or more LEDs that are used to notify the user about events. The
+ * Extension can find information about the LEDs for a certain accessory via the Registration &
+ * Capability API.
+ *
+ * If the accessory has LEDs, the Extension can control them via the Control API. The LEDs can be
+ * controlled via the {@link Intents#CONTROL_LED_INTENT}.
+ * Note that the Host Application might overtake the control of the LED at any time if it wants to
+ * show some important notifications to the user, e.g. when the accessory battery level is low.
+ * The Extension is unaware of this so it might still try to control the LEDs but the Host
+ * Application will ignore the calls.
+ *
+ * Our accessories might or might not have a vibrator. The Extension can find this out by checking
+ * the capabilities of the Host Application via the Registration & Capability API. If the accessory
+ * has a vibrator it is controllable via the Control API, {@link Intents#CONTROL_VIBRATE_INTENT}.
+ *
+ * The accessory might have several hardware keys. Your extension will receive the key events when
+ * one of the keys is pressed. The {@link Intents#CONTROL_KEY_EVENT_INTENT} is sent to the Extension when
+ * a user presses a key on the accessory.
+ *
+ * The Intent carries a few parameters, such as the time stamp of the event, the type of event
+ * (press, release and repeat) and also the key code. The accessory might have one or more keypads
+ * defined. Extensions can look this up in the Registration & Capabilities API. Each key will have a
+ * unique key code for identification. Key codes can be found in the product SDK.
+ *
+ * Certain accessories might have a touch display. Extensions can find this information using the
+ * Registration & Capabilities API. The {@link Intents#CONTROL_TOUCH_EVENT_INTENT} is sent to the
+ * Extension when a user taps the accessory display.
+ *
+ * If the {@link Intents#CONTROL_DISPLAY_DATA_INTENT} is used to send images, then touch events with
+ * display coordinates are delivered in the {@link Intents#CONTROL_TOUCH_EVENT_INTENT} intents.
+ * If a swipe gesture is detected then a {@link Intents#CONTROL_SWIPE_EVENT_INTENT} is sent to the
+ * Extension instead.
+ *
+ * If the {@link Intents#CONTROL_PROCESS_LAYOUT_INTENT} is used to send layouts then some Views
+ * in the layout may handle the touch events themselves.
+ * Touch events are for example handled by views that have android:clickable set to to true.
+ * For these views the extension is informed about clicks through the
+ * {@link Intents#CONTROL_OBJECT_CLICK_EVENT_INTENT} intent.
+ * ListViews also handle touch event and report clicks in {@link Intents#CONTROL_LIST_ITEM_CLICK_INTENT}
+ * intents.
+ * Touch events and swipe gestures that are not handled by Views in the layout are sent to the
+ * Extension through {@link Intents#CONTROL_TOUCH_EVENT_INTENT} and
+ * {@link Intents#CONTROL_SWIPE_EVENT_INTENT} intents.
+ *
+ * Since the Extension is controlling the accessory it also controls what is visible on the display.
+ * The content visible to the user comes from the Extension. Basically the Extension sends images to
+ * be displayed on the accessory display. To find out the dimensions of the display and the color depth
+ * it supports the Extension can use the Registration & Capabilities API. The
+ * {@link Intents#CONTROL_DISPLAY_DATA_INTENT} is sent from the Extension when it wants to update the accessory
+ * display. Extensions can also clear the accessory display at any point if they want to by sending
+ * the {@link Intents#CONTROL_CLEAR_DISPLAY_INTENT}.
+ *
+ * The Extension can send images as raw data (byte array) or it can just send the URI of the image to
+ * be displayed. Note that we are using Bluetooth as bearer which means that we can't send that many
+ * frames per second (FPS). Refresh rate of the display can be found in the Registration & Capabilities API.
+ *
+ * Starting with version 2 of the Control API it is possible to send layouts to the accessory as an
+ * alternative to sending images.
+ * The subset of Android layouts that are supported is specified in {@link Intents#EXTRA_DATA_XML_LAYOUT}.
+ * Layouts are sent using {@link Intents#CONTROL_PROCESS_LAYOUT_INTENT}.
+ * The contents of the views in the layouts can be updated using {@link Intents#CONTROL_SEND_IMAGE_INTENT}
+ * and {@link Intents#CONTROL_SEND_TEXT_INTENT}.
+ * When using layouts, click events are delivered as {@link Intents#CONTROL_OBJECT_CLICK_EVENT_INTENT} intents.
+ *
+ * A layout may include a ListView.
+ * The ListView is initiated by sending a {@link Intents#CONTROL_LIST_COUNT_INTENT}.
+ * This intent can include the list items in the {@link Intents#EXTRA_LIST_CONTENT}.
+ * If no {@link Intents#EXTRA_LIST_CONTENT} is provided the Host Application will request
+ * individual list items when needed through {@link Intents#CONTROL_LIST_REQUEST_ITEM_INTENT}.
+ * The Control extension can refresh the list content at any time by sending a new
+ * {@link Intents#CONTROL_LIST_COUNT_INTENT} intent.
+ * This can be done both if additional items should be added or just if the existing items
+ * should be refreshed.
+ * The Control extension is notified about clicks on list items through the
+ * {@link Intents#CONTROL_LIST_ITEM_CLICK_INTENT} intent.
+ *
+ * A ListView and its items must always fill the entire display width.
+ * The height of a list item must be less or equal to the height of the ListView.
+ *
+ * Some lists may support a user initiated refresh.
+ * The {@link Intents#CONTROL_LIST_REFRESH_REQUEST_INTENT} is sent to the extension if
+ * the user performs a manual refresh action.
+ * The extension is expected to check its data source (for example trigger a poll to a server)
+ * and update the list content.
+ * If the number of items is changed a new {@link Intents#CONTROL_LIST_COUNT_INTENT} should be sent.
+ * If only the existing list items should be updated this is done through a number of
+ * {@link Intents#CONTROL_LIST_ITEM_INTENT} intents.
+ *
+ * The Control extension interacts with the Gallery view in the same way as the ListView with the
+ * addition that it is also notified about selected list items through the
+ * {@link Intents#CONTROL_LIST_ITEM_SELECTED_INTENT} intent.
+ *
+ * A Gallery and its items must always fill the entire display width.
+ * The height of a list item must be less or equal to the height of the Gallery.
+ *
+ * This intent should be sent with enforced security by supplying the host application permission
+ * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION}
+ *
+ * Intent-extra data:
+ *
+ * This intent should be sent with enforced security by supplying the host application permission
+ * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION}
+ *
+ * Intent-extra data:
+ * L&f+azI
z!3;c-YR2|Hk!eNsJu{bX+JA<%h8twj15X#nkcwMZr(Wbctia*wm^(L&`~Ux~-ooOu
zR^0xY$ZvbzmP2ETRgG4aqN>#|UyUl||3NXo?^M+C>))CControl API is a part of the Smart Extension APIs
+ *
+ *
+ * Registration
+ * Extension lifecycle
+ *
+ * Controlling the display
+ * Active power save mode
+ * Controlling the LEDs
+ * Controlling the vibrator
+ * Key events
+ * Touch events
+ * Displaying content on the accessory display
+ * Layouts
+ * Lists
+ * Gallery
+ *
+ *
+ *
+ *
+ *
+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ * Intent-extra data: + * + *+ * The Accessory may support several displays. + * The displays can be real displays or emulated displays to provide compatibility for + * Extensions written for other Accessories. + * If several displays are supported the Extension can use {@link #EXTRA_DISPLAY_ID} + * to specify the target display. + * If {@link #EXTRA_DISPLAY_ID} is absent the Host Application will make a selection + * of target display and if necessary scale the image. + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * {@link #EXTRA_LAYOUT_DATA} can be used to update view in the layout with new values. + * The content of the view in the layout can also be updated using {@link #CONTROL_SEND_TEXT_INTENT} and {@link #CONTROL_SEND_IMAGE_INTENT}. + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * {@link #EXTRA_LIST_REFRESH_ALLOWED} specifies if the user is allowed + * to manually initiate a refresh of the list content. The default + * behavior is that the user is not allowed to initiate a refresh. + * The extension is notified about a refresh request through the + * {@link #CONTROL_LIST_REFRESH_REQUEST_INTENT} intent. + *
+ *+ * This intent should be sent with enforced security by supplying the + * host application permission to sendBroadcast(Intent, String). + * {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the + * host application permission to sendBroadcast(Intent, String). + * {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * {@link #EXTRA_LAYOUT_REFERENCE} specifies the ListView and + * {@link #EXTRA_LIST_ITEM_POSITION} specifies the position to update. + * {@link #EXTRA_DATA_XML_LAYOUT} specifies the layout of the list item. + * {@link #EXTRA_LAYOUT_DATA} can be used to update views in the list + * item layout with new values. + *
+ *+ * This intent should be sent with enforced security by supplying the + * host application permission to sendBroadcast(Intent, String). + * {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the + * host application permission to sendBroadcast(Intent, String). + * {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AHA_PACKAGE_NAME = "aha_package_name"; + + /** + * The name of the Intent-extra used to identify the Extension. + * The Extension will send its package name + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AEA_PACKAGE_NAME = "aea_package_name"; + + /** + * The name of the Intent-extra carrying the state of the display + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_LED_ID = "led_id"; + + /** + * The name of the Intent-extra carrying the color you want the LED to blink with + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_LED_COLOR = "led_color"; + + /** + * The name of the Intent-extra carrying the "on" duration in milliseconds + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_ON_DURATION = "on_duration"; + + /** + * The name of the Intent-extra carrying the "off" duration in milliseconds + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_OFF_DURATION = "off_duration"; + + /** + * The name of the Intent-extra carrying the number of repeats of the on/off pattern. + * Note, the value {@link #REPEAT_UNTIL_STOP_INTENT} means that the on/off pattern is repeated until + * the {@link #CONTROL_STOP_VIBRATE_INTENT} or {@link #CONTROL_STOP_LED_INTENT} intent is received + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_REPEATS = "repeats"; + + /** + * The name of the Intent-extra used to identify the URI of the image to be displayed on the + * accessory display. If the image is in raw data (e.g. an array of bytes) use + * {@link #EXTRA_DATA} instead + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_DATA_URI = "data_uri"; + + /** + * The name of the Intent-extra used to identify the data to be displayed on the accessory + * display. This Intent-extra should be used if the image is in raw data (e.g. an array of bytes) + *+ * TYPE: BYTE ARRAY + *
+ * @since 1.0 + */ + static final String EXTRA_DATA = "data"; + + /** + * The name of the Intent-extra used to identify the pixel offset from the left side of the accessory + * display + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_X_OFFSET = "x_offset"; + + /** + * The name of the Intent-extra used to identify the pixel offset from the top of the accessory + * display + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_Y_OFFSET = "y_offset"; + + /** + * The name of the Intent-extra used to identify the type of key event + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER (long) + *
+ * @since 1.0 + */ + static final String EXTRA_TIMESTAMP = "timestamp"; + + /** + * The name of the Intent-extra used to identify the keycode. + * Information about what type of keypad a accessory has can be found using the + * Registration & Capabilities API + *+ * ALLOWED VALUES: + * Any key code defined in the {@link KeyCodes} interface. + *
+ *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_KEY_CODE = "key_code"; + + /** + * The name of the Intent-extra used to indicate the touch action + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_X_POS = "x_pos"; + + /** + * The name of the Intent-extra used to carry the Y coordinate of the touch event + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_Y_POS = "y_pos"; + + /** + * The name of the Intent-extra used to carry the error code + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * This is a standard Android layout, where a subset of the Android views are supported. + *
+ *+ * The px dimensions is the only dimension supported. + * The only exception is text sizes which can be specified using sp to indicate that the text + * shall be scaled to the user preference setting on the accessory. + *
+ *+ * The following ViewGroups are supported: + *
+ * The following Views are supported: + *
+ * The following View XML attributes are supported + *
+ * For an ImageView the following XML attributes are supported + *
+ * For a TextView the following XML attributes are supported + *
+ * For a ListView and a Gallery there are some additional limitations. + * These views always have to fill the entire display width. + * The items in these views also have to fill the entire display width. + * The height of an item may not be larger than the height of the parent view. + *
+ *+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_DATA_XML_LAYOUT = "data_xml_layout"; + + /** + * The name of the Intent-extra used to identify a reference within a layout. + * Corresponds to the android:id XML attribute in the layout. + *+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_LAYOUT_REFERENCE = "layout_reference"; + + /** + * The name of the Intent-extra used when sending a text (String) + * from the extension to the accessory. The accessory will map the text + * to a layout reference. + *+ * TYPE: STRING + *
+ * @since 2.0 + */ + static final String EXTRA_TEXT = "text_from extension"; + + /** + * The name of the Intent-extra used for indicating the status of the Active Power State Mode. + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: Array of BUNDLEs with following information in each BUNDLE. + *
+ * TYPE: Array of BUNDLEs with following information in each BUNDLE. + *
+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER + *
+ * + * @since 2.0 + */ + static final String EXTRA_LIST_ITEM_ID = "list_item_id"; + + /** + * The position in a list. The position is in the range from 0 to the + * {@link #EXTRA_LIST_COUNT}-1. + *+ * TYPE: INTEGER + *
+ * + * @since 2.0 + */ + static final String EXTRA_LIST_ITEM_POSITION = "list_item_position"; + + /** + * The number of items in a list. + *+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_LIST_COUNT = "list_count"; + + /** + * Reference to a view in a list item layout. + * Corresponds to the android:id XML attribute in the layout. + *+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_LIST_ITEM_LAYOUT_REFERENCE = "list_item_layout_reference"; + + /** + * If true then the user is allowed to initiate a refresh of the list + * content. (For example by a pull to refresh gesture.) + *+ * TYPE: BOOLEAN + *
+ * + * @since 2.0 + */ + static final String EXTRA_LIST_REFRESH_ALLOWED = "list_referesh_allowed"; + + /** + * The id of the display. + * Refers to {@link Registration.DisplayColumns#_ID}. + *+ * TYPE: INTEGER (int) + *
+ * @since 2.0 + */ + static final String EXTRA_DISPLAY_ID = "displayId"; + + /** + * The URI of an icon (40x40 pixels) for a menu item. + * + *+ * TYPE: TEXT + *
+ * + * @since 2.0 + */ + static final String EXTRA_MENU_ITEM_ICON = "menuItemIcon"; + + /** + * The text for a menu item. + * + *+ * TYPE: TEXT + *
+ * + * @since 2.0 + */ + static final String EXTRA_MENU_ITEM_TEXT = "menuItemText"; + + /** + * A unique identity of a menu item assigned by the extension. + *+ * TYPE: INTEGER + *
+ * + * @since 2.0 + */ + static final String EXTRA_MENU_ITEM_ID = "menuItemId"; + + /** + * Items for a menu. Each menu item can either be an icon or a text + * string. The {@link #EXTRA_MENU_ITEM_ID} is used to identify the + * selected menu item. {@link Registration.DisplayColumns#MENU_ITEMS} + * specifies the number of menu items supported by the display. + *+ * TYPE: Array of BUNDLEs with following information in each BUNDLE. + *
Notification is a part of the Smart Extension APIs. + * The Notification engine enables the gathering of event-type data from different + * sources to one place so that accessory host applications will be able to + * access this data, instead of getting the data from each individual source. + * Examples of event-data are activity streams on a social network, new incoming + * SMS and MMS message notifications, a missed call notification, etc. + *
+ *+ * Application developers who wish to have their event-data presented by + * accessories (granted with the permission to access the Notification + * engine's data) should input their application's data according to the + * schema defined by the Notification API. + *
+ *+ * The following diagram shows the position of the Notification API in its + * operating context. + *
+ *
+ *
+ *
+ * Extensions contribute their data using the set format dictated by the Notification API. + * As they are standalone Android applications in their own right, + * extensions may be uninstalled any time, unless they are part of the system + * image, and may be installed any time during the operation of the device. They + * may be 'disabled' as well by the end user via the user interface or by the + * extension developer; when 'disabled', data from that extension may not be + * displayed by the accessory host applications. + *
+ *+ * The accessory host applications provide the functionality to control and + * present the data that is collected by the notification engine. Depending on the + * purpose of the application, the notification engine may not be the only data + * source the application interacts with. Accessory host applications have + * read-access to the data provided by all the extensions, including the right to + * update some of the data fields. Due to this reason, access needs to be controlled + * and restricted so that unwanted information leaks are prevented; + * this is done through the use of a permission. + *
+ *+ * The purpose of the engine is to provide a central store for event-data from + * different sources that is of interest to present to the end user. The reasons + * for choosing such a design are accessory host application performance and data + * security. Cross-database queries are slow and even slower when there are + * potentially many databases involved and this will severely impact the + * performance of accessories and their perceived user experience. + * It is difficult and practically impossible to allow the 'correct' + * applications to access the extension-data when there are many databases to + * interact with. However tempting it may be, the purpose of the engine is NOT to + * be a central store for all kinds of data, e.g. files, media etc., such that it + * will be a "store room" for all kinds of extension-data. + *
+ *Topics covered here: + *
+ * There are three fundamental concepts in the Notification engine's database + * extension developers are required to understand. + *
+ *+ * The concept of Extension is on Android APK level. The extension table + * of the registration database contains meta-information about each extension. + * The purpose of the extension is to provide the necessary data to the notification + * engine set by the database schema. The source of the extension's event-data may + * be self-generated, other Android ContentProvider, a Web server or a combination of + * these. The extension is a standalone application which may have its own GUI that + * also has the capability to provide data to be shown by a host application + * using the Notification engine, or it may not have its own GUI and it is + * completely dependent on the host applications that use the Notification engine to + * present its data. + *
+ *+ * Source is a logical abstraction introduced to enable extension developers + * who want to distinguish the presentation of data connected to different + * backends but retain the ability to package these in a standalone APK. A use + * case example is an email aggregator extension that allows the user to connect to + * different email accounts through the installation of only one Android package + * file; each email account can be set as a Source or the extension defines only + * one Source. In the latter scenario, emails from all accounts may be shown + * in one view instead of separate views. {@link Source} stores attribute + * information about a Source. The accessory host application may use this + * information to filter event-data by Source or provide + * configuration options on the user interface to filter event-data by + * Source.Extension developers who wish to have the accessory host + * application display events from different Sources + * clearly should add {@link Source} information. + * Up to 8 sources can be linked to a Extension. + * If the limit + * is reached, an exception will be thrown. A Source always has to be + * linked to an Extension . + *
+ *+ * An Event is a representation of a notification that may be noteworthy + * to present to the end user. Examples of events are incoming SMS + * message notifications, a missed call notification, updates from friends on a + * social network etc. {@link Event} is used to store events provided + * by the extensions. The accessory host application typically uses the information + * in this table to present the data. An Event is always connected + * to a Source but a Source may not always have to have an + * Event. + * Maximum 100 events from a Source + * stored in {@link Event}; when the limit is reached, events will be automatically + * removed. + *
+ *
+ *
+ * + * Extensions only use the Android ContentResolver API to communicate with the + * Notification engine's ContentProvider. For the possibility to react to user + * input, extensions should implement at least an Android BroadcastReceiver to + * catch Intents sent from the accessory host + * applications. Also see the Control API, Widget API and Sensor API documentation. + *
+ *+ * The list and descriptions of each BroadcastIntent extensions could listen to + * are found in {@link Intents} together with the Intent-extra data + * that are sent in each Intent. + *
+ * + *+ * In order to use the Notification API, an extension must first add information + * in the extension table. This require a specific permission. See the documentation + * of the Registration API for more information + *
+ *+ * A extension only has access to its own data: it is able to insert, query, update + * and remove its data that is stored on the Notification engine. When an + * application registered as a extension is uninstalled from the Android system, + * the associated data that is stored in the engine is automatically removed + * by the Notification engine's implementation. + *
+ *+ * If a extension developer wishes to allow another application to access its data + * on the engine through the use of sharedUserId, it is possible to do so + * though not recommended. When these two or more applications are registered as + * extensions, the Notification engine's security mechanism will only treat these + * extensions as one extension and the extension developer is responsible for any leakage + * or misuse of its information stored in the Notification engine's content + * provider. + *
+ *+ * Extension developers are free to sign their applications with their own + * certificate. + *
+ * + *+ * Before an application can take full advantage of the Notification engine, + * it must tell the engine that it exists and for the engine to have a record + * of this application's attributes. This process is known as registration and + * after a successful registration, the application is referred as an extension in + * the Notification engine's context. In practice, the process of registering + * a extension involves the application inserting some data about itself using the + * Registration API. + *
+ *+ * From the Notification engine's perspective, the life cycle of a extension starts + * from the time a successful registration takes place to the time the Android + * system uninstalls the application or the extension deregisters itself from the + * Notification engine. During this time, the extension is free to access the Event + * Stream engine and receive Intents from it. + *
+ * + *+ * As explained in an earlier section, Source is a logical abstraction + * introduced to easily enable the presentation of event-data originating from + * different backend. It is up to the extension developer to decide how to segment + * the event-data contributed by that extension, but all event-data must be connected + * to a Source, or else the insert operation for event-data will fail. + *
+ *+ * Setting the Source information in the ContentProvider should take place after + * the extension is successfully registered and before inserting event-data. + *
+ * ContentValues values = new ContentValues(); + * Builder iconUriBuilder = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) + * .authority(getPackageName()) + * .appendPath(Integer.toString(R.drawable.icon)); + * + * values.put(SourceColumns.NAME, "RSS news feed"); + * values.put(SourceColumns.ENABLED, "1"); + * values.put(SourceColumns.ICON_URI_1, iconUriBuilder.toString()); + * + * ... + * + * uri = cr.insert(Source.URI, values); + *+ * + * + *
+ * The name of the Intent is {@link Intents#REFRESH_REQUEST_INTENT}. + * Define your BroadcastReceiver to receive this Intent if you wish to rely on this to + * trigger the event-data retrieval. Do not rely on the interval when this Intent is sent + * as it may be arbitrary and completely dependent on the implementation of the Intent sender. + * However it is always sent when a host application is started and an extension can use this to start + * collecting data and continue to be be active. + *
+ *+ * When your extension has event-data to insert to the Notification engine's + * ContentProvider, it may use + * {@link android.content.ContentResolver#insert(Uri, android.content.ContentValues)} + * or {@link android.content.ContentResolver#bulkInsert(Uri, android.content.ContentValues[])}. + * The latter method is recommended for performance reasons to use when there are many + * rows of event-data to insert. + *
+ * ContentResolver cr = getContentResolver(); + * ContentValues[] valueArray = new ContentValues[count]; + * < fill valueArray with data > + * cr.bulkInsert(Event.URI, valueArray); + *+ * + *
+ * When retrieving event-data from the data source, it is highly recommended your + * extension updates and retrieves other relevant data from the same data source, + * e.g. the user's latest status update, at around the same time. This is to + * minimize network signaling traffic and latency. It is also costly for battery + * consumption if there is too frequent network signaling activity. + *
+ *+ * If you need to synchronize periodically with a server in a network, consider + * using the {@link android.app.AlarmManager} to achieve optimal power consumption. + * A tutorial explaining how you can implement this is posted at the + * + * Sony Ericsson Developer blog. + *
+ * + *+ * The event-data supplied by your plug-in in {@link Event} may be a snapshot of + * the information and the user has limited possibilities to interact with the + * information presented by the accessory host application. The user may wish to + * see all details related to that event and react to it, e.g. mark it as a + * favorite, reply, watch the video etc. If your extension offers the user the + * opportunity to interact with the event in your application or on a website, + * listen for the {@link Intents#VIEW_EVENT_INTENT} Intent. This Intent + * is sent by the accessory host application when the user performs an action + * signaling the intention to view the event details. The Intent contains Intent- + * data about the specific event-data that will enable your extension to launch the + * detail view of that event. + *
+ *+ * The location of images is represented as a string. Images may be stored + * locally on the device or on the SD card. + *
+ *+ * The following URI schemes are supported: + *
+ *+ * In order to have a consistent database, the Notification Engine will enforce + * database data integrity upon any data inserted or updated by extensions. This is + * especially true for foreign keys. As an example, sourceId for an + * Event is a foreign key to the column _id in the Source + * table, thus the source_id must have a valid reference to a row in the + * Source table which in turn is associated with a plug-in. If values for + * the stated mandatory columns are not provided, SQLExceptions with constraint + * failures will be thrown. + *
+ * + *+ * For best performance, it is recommended the extension developer use + * {@link android.content.ContentResolver#bulkInsert(Uri, android.content.ContentValues[])} + * or {@link android.content.ContentResolver#applyBatch(String, java.util.ArrayList)} + * when doing inserts or updates to the Event Stream's ContentProvider. + *
+ */ +public class Notification { + + /** + * @hide + * This class is only intended as a utility class containing declared constants + * that will be used by notification extension developers. + */ + protected Notification(){ + } + + /** + * Authority for the Notification provider. + * + * @since 1.0 + */ + public static final String AUTHORITY = "com.sonyericsson.extras.liveware.aef.notification"; + + /** + * Base URI for the Notification provider. + * + * @since 1.0 + */ + protected static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY); + + /** + * Broadcast Intents sent to extensions by the host application. + */ + public interface Intents { + + /** + * Intent sent by the host application to the relevant extension + * to display all details related to the event + *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_EVENT_ID = "event_id"; + + /** + * The name of the Intent-extra used to identify which Source an + * Event is associated with + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_SOURCE_ID = "source_id"; + + /** + * The action requested by the user. + * This is a string indicating a user action + * corresponding to one of the three actions that are + * defined in the source table + * action_1 {@link SourceColumns#ACTION_1} + * action_2 {@link SourceColumns#ACTION_2} + * action_3 {@link SourceColumns#ACTION_3} + * action_icon_1 {@link SourceColumns#ACTION_ICON_1} + * action_icon_2 {@link SourceColumns#ACTION_ICON_2} + * action_icon_3 {@link SourceColumns#ACTION_ICON_3} + *+ * ALLOWED VALUES: + *
+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_EXTENSION_KEY = "extension_key"; + + /** + * The name of the Intent-extra used to identify the Host Application. + * The Host Application will send its package name + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AHA_PACKAGE_NAME = "aha_package_name"; + + /** + * Constant defining an action requested by the host application + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * The action corresponds the action that is + * defined in the source table action_1 {@link SourceColumns#ACTION_1} + * or action_icon_1 {@link SourceColumns#ACTION_ICON_1} + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTENSION_ACTION_1 = "action_1"; + + /** + * Constant defining an action requested by the host application + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * The action corresponds the action that is + * defined in the source table action_2 {@link SourceColumns#ACTION_2} + * or action_icon_2 {@link SourceColumns#ACTION_ICON_2} + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTENSION_ACTION_2 = "action_2"; + + /** + * Constant defining an action requested by the host application + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * The action corresponds the action that is + * defined in the source table action_3 {@link SourceColumns#ACTION_3} + * or action_icon_3 {@link SourceColumns#ACTION_ICON_3} + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTENSION_ACTION_3 = "action_3"; + } + + /** + * Definitions used for interacting with the Extension-table. + * + */ + public interface Source { + + /** + * The source table name + */ + static final String TABLE_NAME = "source"; + + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-source"; + + /** + * Path segment + */ + static final String SOURCES_PATH = "source"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, SOURCES_PATH); + } + + /** + * Column-definitions for the Source table. + */ + public interface SourceColumns extends BaseColumns { + + /** + * Displayable name of the source + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String NAME = "name"; + + /** + * Each Source can use up to 2 icons with different + * sizes and one monochrome + * This is the URI of the largest icon (30x30 pixels) + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ICON_URI_1 = "iconUri1"; + + /** + * Each Source can use up to 2 icons with different + * sizes and one monochrome + * This is the URI of the second largest icon (18x18 pixels) + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ICON_URI_2 = "iconUri2"; + + /** + * Each Source can use up to 2 icons with different + * sizes and one monochrome + * This is the URI of the monochrome icon (18x18 pixels) + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ICON_URI_BLACK_WHITE = "iconUriBlackWhite"; + + /** + * Indicates if the source is enabled + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String ENABLED = "enabled"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the text for the action. + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ACTION_1 = "action_1"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the text for the action. + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ACTION_2 = "action_2"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the text for the action. + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String ACTION_3 = "action_3"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the URI for the action icon (40x40 pixels). + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 2.0 + */ + static final String ACTION_ICON_1 = "action_icon_1"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the URI for the action icon (40x40 pixels). + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 2.0 + */ + static final String ACTION_ICON_2 = "action_icon_2"; + + /** + * Action supported by the extension. + * The action is defined by the extension and supported + * for this source. + * Actions are sent to the extension from host applications + * using the {@link Intents#VIEW_EVENT_INTENT} intent. + * This is the URI for the action icon (40x40 pixels). + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 2.0 + */ + static final String ACTION_ICON_3 = "action_icon_3"; + + /** + * The time (in milliseconds since January 1, 1970 00:00:00 UTC UNIX + * EPOCH) when an event linked to this source was created. + * Shall be stored as GMT+0 time + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String UPDATE_TIME = "updateTime"; + + /** + * Text to speech specific text. + * The text in this column is used in combination + * with the events of the source to create speech events. + * The text in this column is read out before the events + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String TEXT_TO_SPEECH = "textToSpeech"; + + /** + * Extension specific identifier of the source + * It is up to the extension to define this identifier + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String EXTENSION_SPECIFIC_ID = "extension_specific_id"; + + /** + * The color associated with this source. + * This color will be used when visualizing the source and the events associated with it. + * The color shall be sent in the format specified in {@link android.graphics.Color}. + * There is no support for transparency (alpha is ignored). If not set the color is + * determined by the host application. + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * @since 2.0 + */ + static final String COLOR = "color"; + + /** + * The package name of a plug-in. + * If an extension supports shared user id, the package name + * must be specified + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL (REQUIRED if shared user id is used by extension) + *
+ * @since 1.0 + */ + static final String PACKAGE_NAME = "packageName"; + + /** + * If true it is possible for the user to trigger a manual refresh of events from this + * source. + * The manual refresh can for example be used to trigger a new poll to a server. + * The {@link Intents#REFRESH_REQUEST_INTENT} is sent to the extension when the user has + * initiated a refresh. + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL (Default behavior is FALSE) + *
+ * @since 2.0 + */ + static final String SUPPORTS_REFRESH = "supportsRefresh"; + } + + /** + * Definitions used for interacting with the event table. + * + */ + public interface Event { + + /** + * The event table name + */ + static final String TABLE_NAME = "event"; + + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-event"; + + /** + * Path segment + */ + static final String EVENTS_PATH = "event"; + + /** + * Path segment + */ + static final String EVENT_READ_STATUS_PATH = "read_status"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, EVENTS_PATH); + + /** + * Content URI used to observe changes in EVENT_READ_STATUS + */ + static final Uri READ_STATUS_URI = Uri.withAppendedPath(BASE_URI, EVENT_READ_STATUS_PATH); + } + + /** + * Column-definitions for the event table. + */ + public interface EventColumns extends BaseColumns { + + /** + * The ID of the host source corresponding to + * this event + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: MANDATORY + *
+ * + * @since 1.0 + */ + static final String SOURCE_ID = "sourceId"; + + /** + * Short text describing the title for event linked with this data row. + * This can be the phone number, username, email address etc + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String TITLE = "title"; + + /** + * Content URI to an image linked with the event at this data row + * + *+ * TYPE: TEXT + *
+ *+ * + * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String IMAGE_URI = "imageUri"; + + /** + * The time (in milliseconds since January 1, 1970 00:00:00 UTC UNIX + * EPOCH) when the content linked with this data row was published on + * the source. Shall be stored as GMT+0 time + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String PUBLISHED_TIME = "publishedTime"; + + /** + * Whether the event linked with this data row is specifically directed + * to the user ("me") or concerns the user ("me"), e.g. received SMS, + * Facebook private message to the logged-in user, Facebook private + * message from the logged-in user, @reply Tweets from the logged-in + * user, user ("me") is tagged in a photo etc + * + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String PERSONAL = "personal"; + + /** + * Message associated with this event + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String MESSAGE = "message"; + + /** + * Geo data associated with this event + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String GEO_DATA = "geoData"; + + /** + * Indicates if the event has been read by the user + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String EVENT_READ_STATUS = "readStatus"; + + /** + * The time (in milliseconds since January 1, 1970 00:00:00 UTC UNIX + * EPOCH) when this row was created. + * The time stamp is set automatically + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: The time stamp is set automatically + *
+ * + * @since 1.0 + */ + static final String TIME_STAMP = "timeStamp"; + + /** + * Displayable name of the user linked with this data row, e.g. full + * name + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1 + */ + static final String DISPLAY_NAME = "display_name"; + + /** + * URI to the profile image of the user linked with this data row + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1 + */ + static final String PROFILE_IMAGE_URI = "profile_image_uri"; + + /** + * A reference to the contacts content provider. + * The reference is a URI to a {@link android.provider.ContactsContract.RawContacts} + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1 + */ + static final String CONTACTS_REFERENCE = "contacts_reference"; + + /** + * Generic data column for use by the plug-in to store information that + * may be used to identify the friend that is at this data row, in its + * domain. See section + * Contact Linking for more information + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1 + */ + static final String FRIEND_KEY = "friend_key"; + } + + /** + * Definitions used for interacting with the source event join query. + * + */ + public interface SourceEvent { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-source-event"; + + /** + * Path segment + */ + static final String SOURCES_EVENTS_PATH = "source_event"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, SOURCES_EVENTS_PATH); + } + + + /** + * Column-definitions for the source event join query. + */ + public interface SourceEventColumns extends SourceColumns, EventColumns { + /** + * The ID of the event in the source event join query. + * + *+ * TYPE: INTEGER (long) + *
+ */ + static final String EVENT_ID = "eventId"; + } + } diff --git a/src/com/sonyericsson/extras/liveware/aef/notification/package-info.java b/src/com/sonyericsson/extras/liveware/aef/notification/package-info.java new file mode 100644 index 0000000..43cb07c --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/notification/package-info.java @@ -0,0 +1,43 @@ +/* +Copyright (C) 2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * The Notification API, part of the Smart Extension APIs for Sony's + * smart accessories, enables gathering of event-type data from different + * sources into one place. This way the accessory host applications will be + * able to access this data from one source, instead of getting the data from + * each individual source. + * + * Refer to {@link com.sonyericsson.extras.liveware.aef.notification.Notification} for a detailed description + * of the Notification API. + */ +package com.sonyericsson.extras.liveware.aef.notification; + diff --git a/src/com/sonyericsson/extras/liveware/aef/registration/Registration.java b/src/com/sonyericsson/extras/liveware/aef/registration/Registration.java new file mode 100644 index 0000000..72f0801 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/registration/Registration.java @@ -0,0 +1,1728 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB +Copyright (C) 2012-2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.sonyericsson.extras.liveware.aef.registration; + +import android.net.Uri; +import android.provider.BaseColumns; + +import com.sonyericsson.extras.liveware.aef.control.Control; +import com.sonyericsson.extras.liveware.aef.widget.Widget; + +/** + *+ * This API is used by accessory extensions and accessory host applications. Typically host applications insert + * and maintain information about the accessories capabilities. Extensions use the capability information + * in order to interact with the accessories in a correct way. Before an extension can interact with an accessory it must + * provide (register) some information needed by the host applications. + * The API defines and implements an Android ContentProvider that applications access via the Android ContentResolver API. + * The ContentProvider implementation is backed by a database implementation. + *
+ *Topics covered here: + *
+ * This API is an Android content provider that provides information about the capabilities of the accessories. The information is + * provided by the host applications and are used by the extensions to obtain necessary information in order to interact with the + * accessories through the Control, Sensor and Widget APIs. The content provider contains the tables shown in the picture below. + *
+ *
+ * + * For each accessory there is a corresponding record in the host_application table. A Particular host application is identified + * by its package name. For each host application there is one or more device records in the device table. + * A particular device can support zero or more displays, sensors, leds and inputs, defined in the display, sensor, led and input + * tables respectively. There is a sensor_type table describing each type of sensor and keypad table describing the capabilities if + * the keypads of each input type. The capabilities tables are accessible through the content provider. + *
+ *Capability URI's and description + *
+ * Before an extension can use an accessory, the extension must use the registration API content provider + * to insert a record in the extension table. The URI is defined in the Extension interface {@link Extension#URI} and + * the table scheme is defined in the ExtensionColumns interface {@link ExtensionColumns}. + *
+ *
+ * + * After inserting a record in the extensions table, the extension is ready to use the Notification API. + * No further registration is needed in order to use the Notification API and start writing sources and events. + * More advanced extensions that also want to use any of the Widget API, Control API or Sensor API must also register + * information in the registration table. This should be done for each host application that the extension wants to interact with. + * In order to find out what host applications are available and what capabilities they support, the extension should use the + * capability API. + * The URI of the registration table is defined in the ApiRegistration interface {@link ApiRegistration#URI} and + * the table schema is defined in the ApiRegistrationColumns interface {@link ApiRegistrationColumns}. The extension should provide + * the host application package name and indicate what APIs it will use. + *
+ *+ * Before an application can register itself as an extension, there must be at least one host application installed on the phone. + * This is to prevent that extensions start writing data into the databases when there are no host applications (user has no accessories). + *
+ *+ * The application should register upon reception of the + * {@link Intents#EXTENSION_REGISTER_REQUEST_INTENT} intent. + * This intent is broadcasted when a new application is installed and when a new host application + * has added its capabilities to the tables. + *
+ * + *+ * Smart Extension apps may require configuration by the user before they can fully function. + * For example, the end user might need to login to a service on the Internet before events can be retrieved. + * The Smart Extension app is responsible for providing this configuration UI to be displayed. + *
+ *+ * Host applications have their own configuration UIs from within the configuration UIs of registered + * Smart Extension apps can be reached. + * When registering to the Smart Connect, there is a column in the extension table called + * configurationActivity. + * If your Smart Extension app needs to be configured after it is registered, insert your Android + * Activity class name in this column. + *
+ *+ * ... + * String configName = new ComponentName(getPackageName(), + * RssPluginConfig.class.getName()).flattenToShortString(); + * values.put(ExtensionColumns.CONFIGURATION_ACTIVITY, configName); + * ... + * cr.insert(Extension.URI, values); + *+ *
+ * When the user wishes to launch your configuration UI, the host application will launch the registered Activity. + *
+ * + *+ * Each extension that wants to interact with the Registration & Capabilities API should + * specify a specific plug-in permission in their manifest file {@link Registration#EXTENSION_PERMISSION}. + * The API implements a security mechanism that ensure that each extension only can access their own + * registration and notification data. Sharing information between extensions can be obtained for extensions + * that use the sharedUserId mechanism, however this approach is not recommended. + * Extensions do not have permission to write data in the capability tables, only host applications + * have write access. + *
+ *+ * Android Intents are sent when interaction with the extension is needed. + * See the documentation of the Control API, Widget API, Sensor API and + * Notification API for more information about intents. + * To enable the extension to verify the sender of the + * Intents is a trusted application with access to the APIs and not a malicious + * application that sends the same Intents on pretext of being a trusted application, + * the {@link ExtensionColumns#EXTENSION_KEY} field allows plug-in developers to store + * something that can be used as identification when the Intents are received. + * Except where {@link android.app.Activity#startActivity(android.content.Intent)} is used, + * this key is attached to every Intent the different accessory host applications send to + * the extension as these applications are granted access to the accessory information. + * The receiving extension should check the value of the key to see if it matches + * what it has. If not, the plug-in should ignore the Intent. This key is + * generated by the extension itself. It should be as unique as possible to + * minimize the risk of several extensions having the key. An extension is free + * to change the key stored in the database that it owns. As an added precaution, + * Intents are sent as directed Intents where possible. + *
+ */ + +public class Registration { + + /** + * @hide + * This class is only intended as a utility class containing declared constants + * that will be used by plug-in developers. + */ + protected Registration(){ + } + + /** + * All extensions should add in their AndroidManifest.xml a+ * Intent-extra data: + *
+ *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AHA_PACKAGE_NAME = "aha_package_name"; + + /** + * The name of the Intent-extra used to identify the + * accessory connection status + *+ * The value must one the predefined constants + * {@link AccessoryConnectionStatus}. + *
+ * TYPE: INT + *
+ * @since 1.0 + */ + static final String EXTRA_CONNECTION_STATUS = "connnection_status"; + + /** + * This Intent-extra is used when the settings + * of an extension is to be displayed by means + * of starting the activity defined in the + * {@link ExtensionColumns#CONFIGURATION_ACTIVITY} of the extension. + * The Intent-extra is only valid for extensions that support the + * notification API. + * + * This extra indicates if the accessory supports showing notifications history. + *+ * The value can be true (default) or false. + * If false, the accessory does not support showing the history of notifications + * and a notification extension might want to hide e.g. "Clear history" from its settings + *
+ * TYPE: BOOLEAN + *
+ * @since 1.0 + */ + static final String EXTRA_ACCESSORY_SUPPORTS_HISTORY = "supports_history"; + + /** + * This Intent-extra is used when the settings + * of an extension is to be displayed by means + * of starting the activity defined in the + * {@link ExtensionColumns#CONFIGURATION_ACTIVITY} of the extension. + * The Intent-extra is only valid for extensions that support the + * notification API + * + * This extra indicates if the accessory supports triggering actions + * linked to notification events. For more information about actions see. + * {@link com.sonyericsson.extras.liveware.aef.notification.Notification.SourceColumns#ACTION_1} + *+ * The value can be true (default) or false. + * If false, the accessory does not support triggering actions from notification events + * and a notification extension might want to hide action related settings + *
+ * TYPE: BOOLEAN + *
+ * @since 1.0 + */ + static final String EXTRA_ACCESSORY_SUPPORTS_ACTIONS = "supports_actions"; + } + + /** + * Interface used to define constants for + * accessory connection status + */ + public interface AccessoryConnectionStatus { + /** + * The accessory is disconnected from the + * host application + */ + static final int STATUS_DISCONNECTED = 0; + + /** + * The accessory is connected to the + * host application + */ + static final int STATUS_CONNECTED = 1; + } + + /** + * Definitions used for interacting with the Extension-table + * + */ + public interface Extension { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-extensions"; + + /** + * Path segment + */ + static final String EXTENSIONS_PATH = "extensions"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, EXTENSIONS_PATH); + } + + /** + * Column-definitions for the Extension table + */ + public interface ExtensionColumns extends BaseColumns { + + /** + * Displayable name of the extension that may be presented, e.g. in + * settings + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String NAME = "name"; + + /** + * Class name of the Android Activity that contains the settings of the extension + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String CONFIGURATION_ACTIVITY = "configurationActivity"; + + /** + * Short text to describe the current configuration state of the extension + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String CONFIGURATION_TEXT = "configurationText"; + + /** + * URI of the Android launcher icon representing the extension. + * This icon is used by the host application when listing extensions + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String HOST_APP_ICON_URI = "iconLargeUri"; + + /** + * URI of the icon representing the extension. + * This icon is used on the accessory UI. + * The size is 36x36 pixels + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String EXTENSION_ICON_URI = "extensionIconUri"; + + /** + * URI of the icon representing the extension. + * This icon is used on the accessory UI. + * The size is 48x48 pixels. + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 2.0 + */ + static final String EXTENSION_48PX_ICON_URI = "extension48PxIconUri"; + + /** + * URI of the monochrome icon representing the extension. + * This icon is used on the accessory UI. + * The size is 18x18 pixels + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String EXTENSION_ICON_URI_BLACK_WHITE = "extensionIconUriBlackWhite"; + + /** + * Used for security reasons for the extension's benefit. If set, this key + * will be sent as an extra-data in Intents sent to the extension from + * the host application. This enables the extension to verify that the + * sender has valid access to the registration content provider. + * See section Security + * for more information + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String EXTENSION_KEY = "extension_key"; + + /** + * API version. If the extension uses the notification API, this field + * should tell what version of the notification API that is used. + * Value 0 means that the API is not used + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String NOTIFICATION_API_VERSION = "notificationApiVersion"; + + /** + * The package name of an extension. + * If an extension supports shared user id, the package name + * must be specified + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL (REQUIRED if shared user id is used by extension) + *
+ * + * @since 1.0 + */ + static final String PACKAGE_NAME = "packageName"; + + /** + * Specifies the preferred launch mode for extensions that supports both the + * Control and the Notification API. + * This value is ignored for extensions that only supports one of these APIs. + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * PRESENCE: OPTIONAL (REQUIRED if shared user id is used by extension) + *
+ * + * @since 2.0 + */ + static final String LAUNCH_MODE = "launchMode"; + + } + + /** + * Definitions used for interacting with the ApiRegistration-table + * + */ + public interface ApiRegistration { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-registration"; + + /** + * Path segment + */ + static final String EXTENSIONS_PATH = "registrations"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, EXTENSIONS_PATH); + } + + /** + * Column-definitions for the ApiRegistration-table + */ + public interface ApiRegistrationColumns extends BaseColumns { + + /** + * The ID of the extension corresponding to + * this registration + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String EXTENSION_ID = "extensionId"; + + /** + * Package name name of the Accessory Host Application that + * this registration is registered to interact with + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String HOST_APPLICATION_PACKAGE = "hostAppPackageName"; + + /** + * API version. If the the widget API is used, this field + * should tell what version of the widget API that is used. + * Value 0 means that the API is not used + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String WIDGET_API_VERSION = "widgetApiVersion"; + + /** + * API version. If the the control API is used, this field + * should tell what version of the control API that is used. + * Value 0 means that the API is not used + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String CONTROL_API_VERSION = "controlApiVersion"; + + /** + * API version. If the the sensor API is used, this field + * should tell what version of the sensor API that is used. + * Value 0 means that the API is not used + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String SENSOR_API_VERSION = "sensorApiVersion"; + + /** + * Indicates if the extension (control) supports + * Active Low Power. In such cases the extension must + * provide a black and white screen to the accessory + * This should be done through a XML layout. + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL (Default false) + *
+ * + * @see Control.Intents#CONTROL_ACTIVE_POWER_SAVE_MODE_STATUS_CHANGED_INTENT + * @see DisplayColumns#SUPPORTS_LOW_POWER_MODE + * @since 2.0 + */ + static final String LOW_POWER_SUPPORT = "lowPowerSupport"; + + /** + * If true presses on the {@link Control.KeyCodes#KEYCODE_BACK} will be sent to the Control + * extension in {@link Control.Intents#CONTROL_KEY_EVENT_INTENT} intents. + * This allows the Control extension to implements its own handling. + * If false a press on the {@link Control.KeyCodes#KEYCODE_BACK} will stop the control. + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL (Default false) + *
+ * + * @since 2.0 + */ + static final String CONTROL_BACK_INTERCEPT = "controlBackIntercept"; + } + + /** + * Definitions used for interacting with the Capabilities-view + * + */ + public interface Capabilities { + + /** + * Data row MIME type for capabilities + */ + static final String CAPABILITIES_MIME_TYPE = "aef-capabilities"; + + /** + * Path segment capabilities as a separate view + */ + static final String CAPABILITIES_PATH = "capabilities"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, CAPABILITIES_PATH); + } + + /** + * Definitions used for interacting with the Host application-table + * + */ + public interface HostApp { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-host_application"; + + /** + * Path segment + */ + static final String HOST_APP_PATH = "host_application"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, HOST_APP_PATH); + } + + /** + * Column-definitions for the Host application table + */ + public interface HostAppColumns extends BaseColumns { + + /** + * The package name of a host application + * + * @since 1.0 + */ + static final String PACKAGE_NAME = "packageName"; + + /** + * The version of a host application + * + * @since 1.0 + */ + static final String VERSION = "version"; + + /** + * API version. If the host application supports the Widget API, this field + * should tell what version of the Widget API that is supported. + * Value 0 means that the API is not supported + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String WIDGET_API_VERSION = "widgetApiVersion"; + + /** + * The maximum supported widget refresh rate + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String WIDGET_REFRESH_RATE = "widgetRefreshrate"; + + /** + * API version. If the host application supports the Control API, this field + * should tell what version of the Control API that is supported. + * Value 0 means that the API is not supported + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String CONTROL_API_VERSION = "controlApiVersion"; + + /** + * API version. If the host application supports the Sensor API, this field + * should tell what version of the Sensor API that is supported. + * Value 0 means that the API is not supported + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String SENSOR_API_VERSION = "sensorApiVersion"; + + /** + * API version. If the host application supports the Notification API, this field + * should tell what version of the Notification API that is supported. + * Value 0 means that the API is not supported + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String NOTIFICATION_API_VERSION = "notificationApiVersion"; + + } + + /** + * Definitions used for interacting with the Device-table + * + */ + public interface Device { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-device"; + + /** + * Path segment + */ + static final String DEVICES_PATH = "device"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, DEVICES_PATH); + } + + /** + * Column-definitions for the Device table + */ + public interface DeviceColumns extends BaseColumns { + + /** + * The ID of the host application corresponding to + * this device + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String HOST_APPLICATION_ID = "hostAppId"; + + /** + * The device model + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String MODEL = "model"; + + /** + * The type of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String TYPE = "type"; + + /** + * The sub-type of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String SUB_TYPE = "subType"; + + /** + * The marketing name of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String MARKETING_NAME = "marketingName"; + + /** + * The vendor of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String VENDOR = "vendor"; + + /** + * The UID of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String UID = "uid"; + + /** + * The firmware version of the device + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String FIRMWARE_VERSION = "firmwareVersion"; + + /** + * The height of the widget image + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String WIDGET_IMAGE_HEIGHT = "widgetImageHeight"; + + /** + * The width of the widget image + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String WIDGET_IMAGE_WIDTH = "widgetImageWidtht"; + + /** + * Indicates if the device has a vibrator + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String VIBRATOR = "vibrator"; + + /** + * Indicates if the device is connected to the + * host application + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String ACCESSORY_CONNECTED = "accessory_connected"; + + /** + * Specifies the XML layout elements that are supported on this device. + * + *+ * TYPE: INTEGER (int, bit field see {@link LayoutSupport}. + *
+ *+ * PRESENCE: OPTIONAL (Default 0) + *
+ * + * @see Control.Intents#EXTRA_DATA_XML_LAYOUT + * @see Widget.Intents#EXTRA_DATA_XML_LAYOUT + * + * @since 2.0 + */ + static final String LAYOUT_SUPPORT = "layoutSupport"; + } + + /** + * Definitions used for interacting with the Display-table + * + */ + public interface Display { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-display"; + + /** + * Path segment + */ + static final String DISPLAYS_PATH = "display"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, DISPLAYS_PATH); + } + + + /** + * Column-definitions for the Display table + */ + public interface DisplayColumns extends BaseColumns { + + /** + * The ID of the device corresponding to + * this display + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DEVICE_ID = "deviceId"; + + /** + * The width of the display + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DISPLAY_WIDTH = "width"; + + /** + * The width of the display + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DISPLAY_HEIGHT = "height"; + + /** + * The number of colors supported by the display + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String COLORS = "colors"; + + /** + * The refresh rate supported by the display + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String REFRESH_RATE = "refreshRate"; + + /** + * The latency of the display + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String LATENCY = "latency"; + + /** + * Indicates if tap touch is supported by the display + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String TAP_TOUCH = "tapTouch"; + + /** + * Indicates if motion touch is supported by the display + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String MOTION_TOUCH = "motionTouch"; + + /** + * Indicates if the display is a real display or an emulated display + * to provide compatibility with other accessories. + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL (Default value is FALSE) + *
+ * + * @since 2.0 + */ + static final String IS_EMULATED = "isEmulated"; + + /** + * Indicates if the display supports active low power mode. + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: OPTIONAL (Default value is FALSE) + *
+ * + * @since 2.0 + */ + static final String SUPPORTS_LOW_POWER_MODE = "supportsLowPowerMode"; + + /** + * Indicates the number of menu items supported by the display. + * 0 means that the accessory does not support showing a menu on this display. + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL (Default value is 0) + *
+ * + * @since 2.0 + * @see Control.Intents#CONTROL_MENU_SHOW + */ + static final String MENU_ITEMS = "menuItems"; + } + + /** + * Definitions used for interacting with the Sensor-table + * + */ + public interface Sensor { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-sensor"; + + /** + * Path segment + */ + static final String SENSORS_PATH = "sensor"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, SENSORS_PATH); + } + + + /** + * Column-definitions for the Sensor table + */ + public interface SensorColumns extends BaseColumns { + + /** + * The ID of the device corresponding to + * this sensor + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DEVICE_ID = "deviceId"; + + /** + * The ID of the SensorType corresponding to + * this sensor + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String SENSOR_TYPE_ID = "sensorTypeId"; + + /** + * The sensor resolution + * + *+ * TYPE: REAL (float) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String RESOLUTION = "resolution"; + + /** + * The minimum delay of the sensor + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String MINIMUM_DELAY = "minimumDelay"; + + /** + * The maximum range of the sensor + * + *+ * TYPE: REAL (float) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String MAXIMUM_RANGE = "maximumRange"; + + /** + * The name of the sensor + * + *+ * TYPE: TEXT + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String NAME = "name"; + + /** + * The ID of the sensor as defined by the Host Application + * this ID is used by the SensorAPI and is not necessarily the same + * value as the ID column + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String SENSOR_ID = "sensorId"; + + /** + * Indicates if the sensor supports interrupt mode + * In interrupt mode, the sensor only sends data when new values + * are available + * + *+ * TYPE: SHORT INTEGER (short) (0= Not supported, 1= Supported) + *
+ *+ * PRESENCE: OPTIONAL + *
+ * + * @since 1.0 + */ + static final String SUPPORTS_SENSOR_INTERRUPT = "sensorInterrupt"; + } + + /** + * Definitions used for interacting with the Led-table + * + */ + public interface Led { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-led"; + + /** + * Path segment + */ + static final String LEDS_PATH = "led"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, LEDS_PATH); + } + + /** + * Column-definitions for the Led-table + */ + public interface LedColumns extends BaseColumns { + + /** + * The ID of the device corresponding to + * this LED + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DEVICE_ID = "deviceId"; + + /** + * The number of colors supported by the LED + * + *+ * TYPE: INTEGER (int) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String COLORS = "colors"; + } + + /** + * Definitions used for interacting with the Input-table + * + */ + public interface Input { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-input"; + + /** + * Path segment + */ + static final String INPUTS_PATH = "input"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, INPUTS_PATH); + } + + /** + * Column-definitions for the Sensor table + */ + public interface InputColumns extends BaseColumns { + + /** + * The ID of the device corresponding to + * an Input + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DEVICE_ID = "deviceId"; + + /** + * The ID of the keypad + * + *+ * TYPE: INTEGER (long) + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String KEY_PAD_ID = "keyPadId"; + + /** + * The enable status of the Input + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String ENABLED = "enabled"; + } + + /** + * Definitions used for interacting with the Sensor-type-table + * + */ + public interface SensorType { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-sensor_type"; + + /** + * Path segment + */ + static final String SENSOR_TYPES_PATH = "sensor_type"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, SENSOR_TYPES_PATH); + } + + /** + * Column-definitions for the SensorType table + */ + public interface SensorTypeColumns extends BaseColumns { + + /** + * The Type. + *+ * The following sensor types are supported: + *
+ *+ * TYPE: TEXT + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String TYPE = "type"; + + /** + * This column value indicates whether the sensor + * sends information of delicate nature + * + *+ * TYPE: BOOLEAN + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String DELICATE_SENSOR_DATA = "delicate_data"; + } + + /** + * Definitions used for interacting with the Keypad-table + * + */ + public interface KeyPad { + /** + * Data row MIME type + */ + static final String MIME_TYPE = "aef-keypad"; + + /** + * Path segment + */ + static final String KEYPADS_PATH = "keypad"; + + /** + * Content URI + */ + static final Uri URI = Uri.withAppendedPath(BASE_URI, KEYPADS_PATH); + } + + /** + * Column-definitions for the Keypad table + */ + public interface KeyPadColumns extends BaseColumns { + + /** + * The Type + * + *+ * TYPE: TEXT (see {@link KeyPadType for allowed values} + *
+ *+ * PRESENCE: REQUIRED + *
+ * + * @since 1.0 + */ + static final String TYPE = "type"; + } + + /** + * Specifies which API that shall be started when launching the extension. + */ + public interface LaunchMode { + /** + * The Control API shall be started when launching the extension. + * + * @since 2.0 + */ + static final int CONTROL = 0; + + /** + * The Notification API shall be started when launching the extension. + * + * @since 2.0 + */ + static final int NOTIFICATION = 1; + } + + /** + * Bit field specifiers for supported layout elements. + */ + public interface LayoutSupport { + /** + * Bit to indicate that android.widget.TextView is supported. + * + * @since 2.0 + */ + static final int TEXT_VIEW = 1; + + /** + * Bit to indicate that android.widget.ImageView is supported. + * + * @since 2.0 + */ + static final int IMAGE_VIEW = 1<<1; + + /** + * Bit to indicate that android.widget.ListView is supported. + * + * @since 2.0 + */ + static final int LIST_VIEW = 1<<2; + + /** + * Bit to indicate that android.widget.Gallery is supported. + * + * @since 2.0 + */ + static final int GALLERY = 1<<3; + } + + /** + * Key pad type specifiers + */ + public interface KeyPadType { + + /** + * Play key. Corresponds to {@link Control.KeyCodes#KEYCODE_PLAY}. + */ + static final String PLAY = "Play"; + + /** + * Next key. Corresponds to {@link Control.KeyCodes#KEYCODE_NEXT}. + */ + static final String NEXT = "Next"; + + /** + * Previous key. Corresponds to {@link Control.KeyCodes#KEYCODE_PREVIOUS}. + */ + static final String PREVIOUS = "Previous"; + + /** + * Volume down key. Corresponds to {@link Control.KeyCodes#KEYCODE_VOLUME_DOWN}. + */ + static final String VOLUME_DOWN = "Volume down"; + + /** + * Volume up key. Corresponds to {@link Control.KeyCodes#KEYCODE_VOLUME_UP}. + */ + static final String VOLUME_UP = "Volume up"; + + /** + * Action key. Corresponds to {@link Control.KeyCodes#KEYCODE_ACTION}. + */ + static final String ACTION = "App"; + + /** + * Back key. Corresponds to {@link Control.KeyCodes#KEYCODE_BACK}. + */ + static final String BACK = "Back"; + } + + /** + * Definitions of sensor types + */ + public interface SensorTypeValue { + /** + * Constant defining the sensor type Accelerometer. + * Sensor data is sent as an array of 3 float values representing + * the acceleration on the x-axis, y-axis and z-axis respectively. + * All values are in SI units (m/s^2) + * For more information about the accelerometer sensor type, + * see {@link android.hardware.Sensor#TYPE_ACCELEROMETER} + * + * @since 1.0 + */ + static final String ACCELEROMETER = "Accelerometer"; + + /** + * Constant defining the sensor type Light. + * Sensor data is sent as one float value representing + * the light level in SI lux units. + * For more information about the light sensor type, + * see {@link android.hardware.Sensor#TYPE_LIGHT} + * + * @since 1.0 + */ + static final String LIGHT = "Light"; + + /** + * Constant defining the sensor type Magnetic Field. Sensor data is sent + * as an array of 3 float values representing the ambient geomagnetic + * field for all three physical axes (x, y, z) in μT. For more + * information about the magnetic field sensor type, see + * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD} + * + * @since 2.0 + */ + static final String MAGNETIC_FIELD = "MagneticField"; + } +} diff --git a/src/com/sonyericsson/extras/liveware/aef/registration/package-info.java b/src/com/sonyericsson/extras/liveware/aef/registration/package-info.java new file mode 100644 index 0000000..58e10c1 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/registration/package-info.java @@ -0,0 +1,43 @@ +/* +Copyright (C) 2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * The Registration API, part of the Smart Extension APIs for Sony's + * smart accessories, defines and implements an Android ContentProvider that + * the app extensions can access via the Android ContentResolver API. Before an + * app extension can interact with an accessory it must provide (register) some + * information needed by the host applications. + * + * Refer to {@link com.sonyericsson.extras.liveware.aef.registration.Registration} for a detailed description + * of the Registration & Capabilities API. + */ +package com.sonyericsson.extras.liveware.aef.registration; + diff --git a/src/com/sonyericsson/extras/liveware/aef/sensor/Sensor.java b/src/com/sonyericsson/extras/liveware/aef/sensor/Sensor.java new file mode 100644 index 0000000..4969bb3 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/sensor/Sensor.java @@ -0,0 +1,366 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB +Copyright (C) 2012-2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.sonyericsson.extras.liveware.aef.sensor; + +import com.sonyericsson.extras.liveware.aef.registration.Registration; + +/** + *+ * The Sensor API is used to send accessory sensor data from a host application to + * an accessory extension. + *
+ *+ * When a host application registers its capabilities, it will declare if it supports + * the Sensor API and what sensors it exposes. + * Extensions can use the Registration and Capability API to query host + * applications for supported sensors. + *
+ *+ * In order to use this API, an application must have registered itself properly in + * the registration content provider, see the Registration and Capabilities API. + *
+ *+ * Sensor data is sent over a LocalSocket. In order to start communication the extension + * should setup a LocalServerSocket {@link android.net.LocalServerSocket} + * in listening mode and send the {@link Intents#SENSOR_REGISTER_LISTENER_INTENT} intent. + * The capability API can be used to query the host application for supported sensors. + * If multiple sensors are used, multiple LocalServerSocket objects must also be used since + * one sensor is bound to exactly one LocalServerSocket. + * When a extension registers a listener it also specifies what sample rate it wants to have. + *
+ *+ * Some sensors support interrupt mode. + * They can be configured to only send sensor data when new values are available. + * The interrupt flag is part of the sensor data registration Intent. + *
+ *+ * To unregister a listener the extension must send the {@link Intents#SENSOR_UNREGISTER_LISTENER_INTENT}. + *
+ *+ * The sensor data is sent from the host application over a LocalSocket and can be accessed + * through an InputStream. + * The data has the following format: + *
+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AEA_PACKAGE_NAME = "aea_package_name"; + + /** + * The name of the Intent-extra used to identify the Sensor. + * The Extension will send the ID of the sensor. The ID must + * be identical to the value of the SENSOR_ID column from the Sensor + * table of a sensor that is attached to the current host application + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_SENSOR_ID = "sensor_id"; + + /** + * The name of the Intent-extra used to identify the name of the Android + * Local Server Socket that is now waiting for a connection from + * the host application + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_SENSOR_LOCAL_SERVER_SOCKET_NAME = "local_server_socket_name"; + + /** + * The name of the Intent-extra used to set the + * preferred delivery rate of the sensor data. + * The value must one the predefined constants + * {@link SensorRates} + * + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_SENSOR_REQUESTED_RATE = "requested_rate"; + + /** + * The name of the Intent-extra used to set the + * sensor interrupt mode. + * The value must one the predefined constants + * {@link SensorInterruptMode} + * + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_SENSOR_INTERRUPT_MODE = "interrupt_mode"; + + /** + * The name of the Intent-extra used to set the + * error code of an error message from the + * host application. + * The value must be one of the predefined constants + * {@link SensorApiErrorCodes} + * + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_ERROR_CODE = "error_code"; + + /** + * The name of the Intent-extra used to identify the Host Application. + * The Host Application will send its package name. + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AHA_PACKAGE_NAME = "aha_package_name"; + } + + /** + * Interface used to define constants for + * sensor rates. + * The extension can chose from one of the + * constants defined in this interface. + */ + public interface SensorRates { + + /** + * Get sensor data as fast as possible + */ + static final int SENSOR_DELAY_FASTEST = 1; + + /** + * Rate suitable for games + */ + static final int SENSOR_DELAY_GAME = 2; + + /** + * Rate suitable for screen orientation changes + */ + static final int SENSOR_DELAY_NORMAL = 3; + + /** + * Rate suitable for user interface + */ + static final int SENSOR_DELAY_UI = 4; + } + + /** + * Interface used to define constants for + * sensor accuracy. + * The accuracy is sent together with the sensor data + * over the local socket connection. + */ + public interface SensorAccuracy { + + /** + * The values returned by this sensor cannot be trusted, + * calibration is needed or the environment will not allow readings + */ + static final int SENSOR_STATUS_UNRELIABLE = 0; + + /** + * This sensor is reporting data with low accuracy, + * calibration with the environment is needed + */ + static final int SENSOR_STATUS_ACCURACY_LOW = 1; + + /** + * This sensor is reporting data with an average level of accuracy, + * calibration with the environment may improve the readings + */ + static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; + + /** + * This sensor is reporting data with maximum accuracy + */ + static final int SENSOR_STATUS_ACCURACY_HIGH = 3; + } + + /** + * Interface used to define constants for + * sensor interrupt mode. + * The interrupt mode is set when registering a listener + */ + public interface SensorInterruptMode { + + /** + * The interrupt mode is disabled, + * e.g. the sensor is sending data continuously + */ + static final int SENSOR_INTERRUPT_DISABLED = 0; + + /** + * The interrupt mode is enabled, + * e.g. no sensor is sent until new sensor data is available + */ + static final int SENSOR_INTERRUPT_ENABLED = 1; + } + + /** + * Interface used to define constants for + * sensor error codes sent from the host application + */ + public interface SensorApiErrorCodes { + + /** + * Error code indicating that the action + * requested by the extension is not allowed + * in the current state + */ + static final int SENSOR_ERROR_CODE_NOT_ALLOWED = 0; + } + + /** + * Constant defining the sensor type Accelerometer. + * Sensor data is sent as an array of 3 float values representing + * the acceleration on the x-axis, y-axis and z-axis respectively. + * All values are in SI units (m/s^2) + * For more information about the accelerometer sensor type, + * see {@link android.hardware.Sensor#TYPE_ACCELEROMETER} + * + * @deprecated + * @see Registration.SensorTypeValue#ACCELEROMETER + */ + public static final String SENSOR_TYPE_ACCELEROMETER = Registration.SensorTypeValue.ACCELEROMETER; + + /** + * Constant defining the sensor type Light. + * Sensor data is sent as one float value representing + * the light level in SI lux units. + * For more information about the light sensor type, + * see {@link android.hardware.Sensor#TYPE_LIGHT} + * + * @deprecated + * @see Registration.SensorTypeValue#LIGHT + */ + public static final String SENSOR_TYPE_LIGHT = Registration.SensorTypeValue.LIGHT; +} diff --git a/src/com/sonyericsson/extras/liveware/aef/sensor/package-info.java b/src/com/sonyericsson/extras/liveware/aef/sensor/package-info.java new file mode 100644 index 0000000..15d80f2 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/sensor/package-info.java @@ -0,0 +1,41 @@ +/* +Copyright (C) 2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * The Sensor API, part of the Smart Extension APIs for Sony's + * smart accessories, is used to send accessory sensor data from a host + * application to an accessory app extension. + * + * Refer to {@link com.sonyericsson.extras.liveware.aef.sensor.Sensor} for a detailed description + * of the Sensor API. + */ +package com.sonyericsson.extras.liveware.aef.sensor; + diff --git a/src/com/sonyericsson/extras/liveware/aef/widget/Widget.java b/src/com/sonyericsson/extras/liveware/aef/widget/Widget.java new file mode 100644 index 0000000..a38c5d2 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/widget/Widget.java @@ -0,0 +1,494 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB +Copyright (C) 2012-2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.sonyericsson.extras.liveware.aef.widget; + +import com.sonyericsson.extras.liveware.aef.registration.Registration.DeviceColumns; +import com.sonyericsson.extras.liveware.aef.registration.Registration.ExtensionColumns; + +/** + *+ * Some of our advanced accessories will support the Widget API. + * The Widget API enables the Extension to display a live image on the + * main menu of the accessory, sort of a preview of what the Extension is about. + *
+ *Topics covered here: + *
+ * Widgets will usually be the building blocks for the main menu of the accessories + * that support Widgets. + * At certain occasions, the Host Application will request a Widget image from the + * Extension, {@link Intents#WIDGET_START_REFRESH_IMAGE_INTENT}. E.g. when the user powers on the accessory, + * or when a new Widget Extension is installed. + * When the Extension receives this Intent, it must send back a Widget image to the Host + * Application, {@link Intents#WIDGET_IMAGE_UPDATE_INTENT} or {@link Intents#WIDGET_PROCESS_LAYOUT_INTENT}. + * The Extension can continue to update its image when it finds it appropriate as long as the intent + * {@link Intents#WIDGET_STOP_REFRESH_IMAGE_INTENT} has not been received. The extension can resume updating + * its image when {@link Intents#WIDGET_START_REFRESH_IMAGE_INTENT} has been received again. + *
+ * + *+ * Before an Extension sends the Widget image to the Host Application, it has to figure out + * what size the image should be. This might vary between accessories as some have a larger + * display. This information can be found using the Registration & Capabilities API. + * Every Host Application will write down its parameters into the Capabilities database. + *
+ * + *+ * In order to allow the user to interact with the Widget, the Extension will get touch events + * that occur when your Widget is in focus on the accessory display, {@link Intents#WIDGET_ONTOUCH_INTENT}. + * This way, the Extension receives user feedback and can adapt, refresh Widget image. + *
+ *+ * As an example, one could mention a media player controller Widget. The initial Widget image shows a couple + * of buttons, play/pause, previous, next, etc. When a user presses somewhere on the Widget, the + * {@link Intents#WIDGET_ONTOUCH_INTENT} will be sent to the Extension. Since the Extension provided the + * initial image, it knows the exact layout/position of the buttons and can that way determine what button + * that was pressed and take action. In this case, it could be to start playing a song. The Extension can + * also choose to update the Widget image so that it reflects the latest state, instead of play button, + * it might show the pause button and the title of the playing song. + *
+ + */ + +public class Widget { + + /** + * @hide + * This class is only intended as a utility class containing declared constants + * that will be used by Widget API Extension developers. + */ + protected Widget() { + } + + /** + * Intents sent between Widget Extensions and Accessory Host Applications. + */ + public interface Intents { + + /** + * Intent sent by the Accessory Host Application whenever it wants the Widget to start update it's Widget image. + * Usually this Intent will be sent out when the accessory just starts and is about to show the Widget menu. + * The Widget image should be updated as soon as possible and after the initial update the Widget image should + * be updated occasionally until WIDGET_STOP_REFRESH_IMAGE_INTENT is received + *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * This intent should be sent with enforced security by supplying the host application permission + * to sendBroadcast(Intent, String). {@link com.sonyericsson.extras.liveware.aef.registration.Registration#HOSTAPP_PERMISSION} + *
+ *+ * Intent-extra data: + *
+ *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AHA_PACKAGE_NAME = "aha_package_name"; + + /** + * The name of the Intent-extra used to identify the Extension. + * The Extension will send its package name + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_AEA_PACKAGE_NAME = "aea_package_name"; + + /** + * The name of the Intent-extra used to identify the URI of the Widget image. + * If the image is in raw data (e.g. an array of bytes) use {@link #EXTRA_WIDGET_IMAGE_DATA} instead. + * The image is displayed in the Widget row on the Accessory display. + * The image can be updated by the Extension at a later stage + *+ * TYPE: TEXT + *
+ * @since 1.0 + */ + static final String EXTRA_WIDGET_IMAGE_URI = "widget_image_uri"; + + /** + * The name of the Intent-extra used to identify the Widget image. + * This Intent-extra should be used if the image is in raw data (e.g. an array of bytes). + * The image is displayed in the Widget row on the Accessory display. + * The image can be updated by the Extension at a later stage + *+ * TYPE: BYTE ARRAY + *
+ * @since 1.0 + */ + static final String EXTRA_WIDGET_IMAGE_DATA = "widget_image_data"; + + /** + * The name of the Intent-extra used to identify the touch event + *+ * TYPE: INTEGER (int) + *
+ *+ * ALLOWED VALUES: + *
+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_EVENT_X_POS = "widget_event_x_pos"; + + /** + * The name of the Intent-extra used to carry the Y coordinate of the touch event + *+ * TYPE: INTEGER (int) + *
+ * @since 1.0 + */ + static final String EXTRA_EVENT_Y_POS = "widget_event_y_pos"; + + /** + * The name of the Intent-extra containing the key set by the extension + * in {@link ExtensionColumns#EXTENSION_KEY}. This Intent-data is present in + * all Intents sent by accessory host application, except where + * {@link android.app.Activity#startActivity(android.content.Intent)} + * is used. See section Security + * for more information + * + * @since 1.0 + */ + static final String EXTRA_EXTENSION_KEY = "extension_key"; + + /** + * The name of the Intent-extra used to identify the data XML layout to be processed by the host application + * and displayed by the accessory. + * The layout resource id is used to identify the layout. + *+ * This is a standard Android layout, where a subset of the Android views are supported. + *
+ * + *+ * The px dimensions is the only dimension supported. + * The only exception is text sizes which can be specified using sp to indicate that the text + * shall be scaled according to the text size setting on the accessory. + *
+ *+ * The following ViewGroups are supported: + *
+ * The following Views are supported: + *
+ * The following View XML attributes are supported + *
+ * For an ImageView the following XML attributes are supported + *
+ * For a TextView the following XML attributes are supported + *
+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_DATA_XML_LAYOUT = "data_xml_layout"; + /** + * The name of the Intent-extra used to identify a reference within an extension. + * The extension may use the same reference in multiple layouts. + * A reference is a text or an image owned by the extension and will + * be used to map between layouts and images/texts. + * Corresponds to the android:id XML attribute in the layout. + *+ * TYPE: INTEGER + *
+ * @since 2.0 + */ + static final String EXTRA_LAYOUT_REFERENCE = "layout_reference"; + + /** + * The name of the Intent-extra used when sending a text (String) + * from the extension to the accessory. The accessory will map the text + * to a layout reference. + *+ * TYPE: STRING + *
+ * @since 2.0 + */ + static final String EXTRA_WIDGET_TEXT = "text_from extension"; + + /** + * The event type is a short tap. + * + * @since 1.0 + */ + static final int EVENT_TYPE_SHORT_TAP = 0; + + /** + * The event type is a long tap + * + * @since 1.0 + */ + static final int EVENT_TYPE_LONG_TAP = 1; + } +} diff --git a/src/com/sonyericsson/extras/liveware/aef/widget/package-info.java b/src/com/sonyericsson/extras/liveware/aef/widget/package-info.java new file mode 100644 index 0000000..ad33fa6 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/aef/widget/package-info.java @@ -0,0 +1,41 @@ +/* +Copyright (C) 2013 Sony Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * The Widget API, part of the Smart Extension APIs for Sony's + * smart accessories, enables the app extension to display a live image on the + * main menu of the accessory (like a preview of the app extension itself). + * + * Refer to {@link com.sonyericsson.extras.liveware.aef.widget.Widget} for a detailed description + * of the Widget API. + */ +package com.sonyericsson.extras.liveware.aef.widget; + diff --git a/src/com/sonyericsson/extras/liveware/extension/util/AefTextView.java b/src/com/sonyericsson/extras/liveware/extension/util/AefTextView.java new file mode 100644 index 0000000..6c3904c --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/extension/util/AefTextView.java @@ -0,0 +1,68 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sonyericsson.extras.liveware.extension.util; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.TextView; + +/** + * This extension of TextView renders text on a single line, and fades end if + * text does not fit. NOTE! This view only supports a single text line and only + * handles gravity left. + */ +public class AefTextView extends TextView { + public AefTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AefTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Force single line, see also setHorizontalFadingEdgeEnabled below + setHorizontallyScrolling(true); + + // remove new lines if any + String text = getText().toString(); + text = text.replaceAll("\\r?\\n", " "); + setText(text); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + float textWidth = getPaint().measureText(getText().toString()); + float availableWidth = getMeasuredWidth(); + + // fade if too long text + setHorizontalFadingEdgeEnabled(textWidth > availableWidth); + } +} diff --git a/src/com/sonyericsson/extras/liveware/extension/util/Dbg.java b/src/com/sonyericsson/extras/liveware/extension/util/Dbg.java new file mode 100644 index 0000000..1d19ac2 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/extension/util/Dbg.java @@ -0,0 +1,92 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.sonyericsson.extras.liveware.extension.util; + +import android.util.Log; + +public final class Dbg { + + public static final boolean DEBUG = true; + + private static String LOG_TAG = "ExtensionUtils"; + + private Dbg() { + } + + private static boolean logEnabled() { + if (DEBUG) { + return Log.isLoggable(LOG_TAG, Log.DEBUG); + } else { + return false; + } + } + + public static void v(String s) { + if (logEnabled()) { + android.util.Log.v(LOG_TAG, s); + } + } + + public static void e(String s) { + if (logEnabled()) { + android.util.Log.e(LOG_TAG, s); + } + } + + public static void e(String s, Throwable t) { + if (logEnabled()) { + android.util.Log.e(LOG_TAG, s, t); + } + } + + public static void w(String s) { + if (logEnabled()) { + android.util.Log.w(LOG_TAG, s); + } + } + + public static void w(String s, Throwable t) { + if (logEnabled()) { + android.util.Log.w(LOG_TAG, s, t); + } + } + + public static void d(String s) { + if (logEnabled()) { + android.util.Log.d(LOG_TAG, s); + } + } + + public static void setLogTag(final String tag) { + LOG_TAG = tag; + } +} diff --git a/src/com/sonyericsson/extras/liveware/extension/util/ExtensionService.java b/src/com/sonyericsson/extras/liveware/extension/util/ExtensionService.java new file mode 100644 index 0000000..0a6fa38 --- /dev/null +++ b/src/com/sonyericsson/extras/liveware/extension/util/ExtensionService.java @@ -0,0 +1,899 @@ +/* +Copyright (c) 2011, Sony Ericsson Mobile Communications AB +Copyright (c) 2012 Sony Mobile Communications AB. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the Sony Ericsson Mobile Communications AB nor the names + of its contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sonyericsson.extras.liveware.extension.util; + +import android.app.Service; +import android.content.Intent; +import android.database.Cursor; +import android.database.SQLException; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; + +import com.sonyericsson.extras.liveware.aef.control.Control; +import com.sonyericsson.extras.liveware.aef.notification.Notification; +import com.sonyericsson.extras.liveware.aef.registration.Registration; +import com.sonyericsson.extras.liveware.aef.registration.Registration.Device; +import com.sonyericsson.extras.liveware.aef.registration.Registration.DeviceColumns; +import com.sonyericsson.extras.liveware.aef.widget.Widget; +import com.sonyericsson.extras.liveware.extension.util.control.ControlExtension; +import com.sonyericsson.extras.liveware.extension.util.control.ControlListItem; +import com.sonyericsson.extras.liveware.extension.util.control.ControlObjectClickEvent; +import com.sonyericsson.extras.liveware.extension.util.control.ControlTouchEvent; +import com.sonyericsson.extras.liveware.extension.util.registration.IRegisterCallback; +import com.sonyericsson.extras.liveware.extension.util.registration.RegisterExtensionTask; +import com.sonyericsson.extras.liveware.extension.util.registration.RegistrationInformation; +import com.sonyericsson.extras.liveware.extension.util.widget.WidgetExtension; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * The extension service is an abstract class that should be extended for + * accessory extensions. + */ +public abstract class ExtensionService extends Service implements IRegisterCallback { + + private class IntentRunner implements Runnable { + protected Intent mIntent; + protected int mRunnerStartId; + + IntentRunner(Intent intent, int startId) { + mIntent = intent; + mRunnerStartId = startId; + } + + /** + * Does nothing should be overridden + */ + @Override + public void run() { + } + } + + public static final int INVALID_ID = -1; + + private RegisterExtensionTask mRegisterTask = null; + + private final String mExtensionKey; + + private RegistrationInformation mRegistrationInformation; + + private HashMap+ * + * This method is mainly aimed for extensions that shares user id and + * process in which case they can access and modify data that belongs to + * other extensions. + *
+ * + * Note that no runtime exceptions, such as {@link SecurityException} and + * {@link SQLException}, will be handled by this method. Exceptions shall + * instead be handled in the calling method if needed. + *
+ * + * This method is also convenient when querying events that belongs to a + * specific {@link Notification.SourceColumns#EXTENSION_SPECIFIC_ID} since + * no extra lookup of the source id is needed. + * + * + * @param context The context + * @param projection A list of which columns to return. Passing null will + * return all columns, which is inefficient. The projection can + * contain all columns in {@link Notification.EventColumns} and + * all columns in {@link Notification.SourceColumns} except for + * {@link Notification.SourceColumns#_ID} + * @param selection A filter declaring which rows to return, formatted as an + * SQL WHERE clause (excluding the WHERE itself). Passing null + * will return all rows for the given URI. + * @param selectionArgs Arguments to where String + * @param sortOrder How to order the rows, formatted as an SQL ORDER BY + * clause (excluding the ORDER BY itself). Passing null will use + * the default sort order, which may be unordered. + * @return A Cursor object, which is positioned before the first entry, or + * null + */ + public static Cursor queryEvents(Context context, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + String extensionWhere = getSourcesWhere(context); + if (!TextUtils.isEmpty(selection)) { + extensionWhere += " AND (" + selection + ")"; + } + return context.getContentResolver().query(Notification.SourceEvent.URI, projection, + extensionWhere, selectionArgs, sortOrder); + } + + /** + * Query {@link Notification.SourceEvent#URI}, limit query to affect events + * in this extension only and sources that are enabled. Returned cursor is a + * join between {@link Notification.Source#URI} and + * {@link Notification.Event#URI}. Queries executed on + * {@link Notification.Event#URI} can also be executed by this method if all + * references to {@link Notification.EventColumns#_ID} are replaced with + * event._id + *
+ * + * This method is mainly aimed for extensions that shares user id and + * process in which case they can access and modify data that belongs to + * other extensions. + *
+ * + * Note that no runtime exceptions, such as {@link SecurityException} and + * {@link SQLException}, will be handled by this method. Exceptions shall + * instead be handled in the calling method if needed. + *
+ * + * This method is also convenient when querying events that belongs to a + * specific {@link Notification.SourceColumns#EXTENSION_SPECIFIC_ID} since + * no extra lookup of the source id is needed. + * + * + * @param context The context + * @param projection A list of which columns to return. Passing null will + * return all columns, which is inefficient. The projection can + * contain all columns in {@link Notification.EventColumns} and + * all columns in {@link Notification.SourceColumns} except for + * {@link Notification.SourceColumns#_ID} + * @param selection A filter declaring which rows to return, formatted as an + * SQL WHERE clause (excluding the WHERE itself). Passing null + * will return all rows for the given URI. + * @param selectionArgs Arguments to where String + * @param sortOrder How to order the rows, formatted as an SQL ORDER BY + * clause (excluding the ORDER BY itself). Passing null will use + * the default sort order, which may be unordered. + * @return A Cursor object, which is positioned before the first entry, or + * null + */ + public static Cursor queryEventsFromEnabledSources(Context context, String[] projection, + String selection, String[] selectionArgs, String sortOrder) { + String where = Notification.SourceEventColumns.ENABLED + " = 1"; + if (!TextUtils.isEmpty(selection)) { + where += " AND (" + selection + ")"; + } + return queryEvents(context, projection, where, selectionArgs, sortOrder); + } + + /** + * Update events, limit update to affect events in this extension only. + *
+ * + * This method is mainly aimed for extensions that shares user id and + * process in which case they can access and modify data that belongs to + * other extensions. + *
+ * + * Note that no runtime exceptions, such as {@link SecurityException} and + * {@link SQLException}, will be handled by this method. Exceptions shall + * instead be handled in the calling method if needed. + * + * @param context The context + * @param values The new field values. The key is the column name for the + * field. A null value will remove an existing field value. + * @param where A filter to apply to rows before updating, formatted as an + * SQL WHERE clause (excluding the WHERE itself). + * @param selectionArgs Arguments to where String + * @return The number of rows updated + */ + public static int updateEvents(Context context, ContentValues values, String where, + String[] selectionArgs) { + String extensionWhere = getEventsWhere(context); + if (!TextUtils.isEmpty(where)) { + extensionWhere += " AND (" + where + ")"; + } + return context.getContentResolver().update(Notification.Event.URI, values, extensionWhere, + selectionArgs); + } + + /** + * Delete events, limit delete to affect events in this extension only. + *
+ * + * This method is mainly aimed for extensions that shares user id and + * process in which case they can access and modify data that belongs to + * other extensions. + *
+ * + * Note that no runtime exceptions, such as {@link SecurityException} and + * {@link SQLException}, will be handled by this method. Exceptions shall + * instead be handled in the calling method if needed. + * + * @param context The context + * @param where A filter to apply to rows before deleting, formatted as an + * SQL WHERE clause (excluding the WHERE itself). + * @param selectionArgs Arguments to where String + * @return The number of rows deleted + */ + public static int deleteEvents(Context context, String where, String[] selectionArgs) { + String extensionWhere = getEventsWhere(context); + if (!TextUtils.isEmpty(where)) { + extensionWhere += " AND (" + where + ")"; + } + return context.getContentResolver().delete(Notification.Event.URI, extensionWhere, + selectionArgs); + + } + + /** + * Get where string that limits a queries to {@link Notification.Event#URI} + * to affect events that belongs to this extension only + * + * @param context The context + * @return The where string: + *
+ * Template: sourceId IN ( sourceId1, sourceId2, ... )
+ */
+ public static String getEventsWhere(Context context) {
+ ArrayList
+ *
+ * This method is mainly aimed for extensions that shares user id and
+ * process in which case they can access and modify data that belongs to
+ * other extensions.
+ *
+ *
+ * Note that no runtime exceptions, such as {@link SecurityException} and
+ * {@link SQLException}, will be handled by this method. Exceptions shall
+ * instead be handled in the calling method if needed.
+ *
+ * @param context The context
+ * @param projection A list of which columns to return. Passing null will
+ * return all columns, which is inefficient.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null
+ * will return all rows for the given URI.
+ * @param selectionArgs Arguments to where String
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use
+ * the default sort order, which may be unordered.
+ * @return A Cursor object, which is positioned before the first entry, or
+ * null
+ */
+ public static Cursor querySources(Context context, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ String extensionWhere = getSourcesWhere(context);
+ if (!TextUtils.isEmpty(selection)) {
+ extensionWhere += " AND (" + selection + ")";
+ }
+ return context.getContentResolver().query(Notification.Source.URI, projection,
+ extensionWhere, selectionArgs, sortOrder);
+ }
+
+ /**
+ * Update sources, limit scope to sources in this extension
+ *
+ *
+ * This method is mainly aimed for extensions that shares user id and
+ * process in which case they can access and modify data that belongs to
+ * other extensions.
+ *
+ *
+ * Note that no runtime exceptions, such as {@link SecurityException} and
+ * {@link SQLException}, will be handled by this method. Exceptions shall
+ * instead be handled in the calling method if needed.
+ *
+ * @param context The context
+ * @param values The new field values. The key is the column name for the
+ * field. A null value will remove an existing field value.
+ * @param where A filter to apply to rows before updating, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself).
+ * @param selectionArgs Arguments to where String
+ * @return The number of rows updated
+ */
+ public static int updateSources(Context context, ContentValues values, String where,
+ String[] selectionArgs) {
+ String extensionWhere = getSourcesWhere(context);
+ if (!TextUtils.isEmpty(where)) {
+ extensionWhere += " AND (" + where + ")";
+ }
+ DeviceInfoHelper.removeUnsafeValues(context, values);
+ return context.getContentResolver().update(Notification.Source.URI, values, extensionWhere,
+ selectionArgs);
+ }
+
+ /**
+ * Delete sources, limit scope to sources in this extension
+ *
+ *
+ * This method is mainly aimed for extensions that shares user id and
+ * process in which case they can access and modify data that belongs to
+ * other extensions.
+ *
+ *
+ * Note that no runtime exceptions, such as {@link SecurityException} and
+ * {@link SQLException}, will be handled by this method. Exceptions shall
+ * instead be handled in the calling method if needed.
+ *
+ * @param context The context
+ * @param where A filter to apply to rows before deleting, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself).
+ * @param selectionArgs Arguments to where String
+ * @return The number of rows deleted
+ */
+ public static int deleteSources(Context context, String where, String[] selectionArgs) {
+ String extensionWhere = getSourcesWhere(context);
+ if (!TextUtils.isEmpty(where)) {
+ extensionWhere += " AND (" + where + ")";
+ }
+ return context.getContentResolver().delete(Notification.Source.URI, extensionWhere,
+ selectionArgs);
+
+ }
+
+ /**
+ * Get where string that limits a queries to {@link Notification.Source#URI}
+ * and {@link Notification.SourceEvents#URI} to affect sources and source
+ * events that belongs to this extension only
+ *
+ * @param context The context
+ * @return The where string
+ */
+ public static String getSourcesWhere(Context context) {
+ return Notification.SourceColumns.PACKAGE_NAME + " = '" + context.getPackageName() + "'";
+ }
+
+}
diff --git a/src/com/sonyericsson/extras/liveware/extension/util/registration/DeviceInfo.java b/src/com/sonyericsson/extras/liveware/extension/util/registration/DeviceInfo.java
new file mode 100644
index 0000000..6410ddf
--- /dev/null
+++ b/src/com/sonyericsson/extras/liveware/extension/util/registration/DeviceInfo.java
@@ -0,0 +1,397 @@
+/*
+Copyright (c) 2011, Sony Ericsson Mobile Communications AB
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the Sony Ericsson Mobile Communications AB nor the names
+ of its contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.sonyericsson.extras.liveware.extension.util.registration;
+
+import com.sonyericsson.extras.liveware.aef.registration.Registration.Display;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.DisplayColumns;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.Input;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.InputColumns;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.KeyPad;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.KeyPadColumns;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.SensorColumns;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.SensorType;
+import com.sonyericsson.extras.liveware.aef.registration.Registration.SensorTypeColumns;
+import com.sonyericsson.extras.liveware.extension.util.Dbg;
+import com.sonyericsson.extras.liveware.extension.util.sensor.AccessorySensor;
+import com.sonyericsson.extras.liveware.extension.util.sensor.AccessorySensorType;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.SQLException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The device info class describes a host application device. This class only
+ * contains a subset of the information available for the device.
+ */
+public class DeviceInfo {
+
+ private final Context mContext;
+
+ private final String mHostAppPackageName;
+
+ private final long mId;
+
+ private final int mWidgetWidth;
+
+ private final int mWidgetHeight;
+
+ private final boolean mVibrator;
+
+ private List
+ * public void startRefresh() {
+ * // Update now and every 10th second
+ * scheduleRepeatingRefresh(System.currentTimeMillis(), 10 * 1000,
+ * SampleWidgetService.EXTENSION_KEY);
+ * }
+ *
+ * public void stopRefresh() {
+ * cancelScheduledRefresh(SampleWidgetService.EXTENSION_KEY);
+ * }
+ *
+ * public void onScheduledRefresh() {
+ * // Update widget...
+ * }
+ *
+ *
+ * @see #scheduleRefresh(long, String)
+ * @see #scheduleRepeatingRefresh(long, long, String)
+ * @see #cancelScheduledRefresh(String)
+ */
+ public void onScheduledRefresh() {
+
+ }
+
+ /**
+ * Utility that creates the pending intent used to schedule a refresh or to
+ * cancel refreshing
+ *
+ * @see #onScheduledRefresh()
+ * @return The pending intent
+ */
+ private PendingIntent createPendingRefreshIntent(String extensionKey) {
+ Intent intent = new Intent(SCHEDULED_REFRESH_INTENT);
+ intent.putExtra(Widget.Intents.EXTRA_EXTENSION_KEY, extensionKey);
+ intent.putExtra(Widget.Intents.EXTRA_AHA_PACKAGE_NAME, mHostAppPackageName);
+ intent.setPackage(mContext.getPackageName());
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ return pi;
+ }
+
+ /**
+ * Schedule a repeating refresh.
+ *
+ * @see #onScheduledRefresh()
+ * @see #scheduleRefresh(long, String)
+ * @see #cancelScheduledRefresh(String)
+ * @param triggerAtTime Time the scheduled refresh should trigger first time
+ * in {@link System#currentTimeMillis()} time.
+ * @param interval Interval between subsequent repeats of the scheduled
+ * refresh.
+ * @param extensionKey The extension key
+ */
+ protected void scheduleRepeatingRefresh(long triggerAtTime, long interval, String extensionKey) {
+ AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+ am.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, interval,
+ createPendingRefreshIntent(extensionKey));
+ }
+
+ /**
+ * Schedule a refresh.
+ *
+ * @param triggerAtTime Time the scheduled refresh should trigger in
+ * {@link System#currentTimeMillis()} time.
+ * @param extensionKey The extension key
+ */
+ protected void scheduleRefresh(long triggerAtTime, String extensionKey) {
+ AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+ am.set(AlarmManager.RTC_WAKEUP, triggerAtTime,
+ createPendingRefreshIntent(extensionKey));
+ }
+
+ /**
+ * Cancel any pending scheduled refresh associated with the extension key.
+ *
+ * @param extensionKey The extension key
+ */
+ protected void cancelScheduledRefresh(String extensionKey) {
+ AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mgr.cancel(createPendingRefreshIntent(extensionKey));
+ }
+
+ /**
+ * Take action based on request code
+ *
+ * @see WidgetReceiver#doActionOnAllWidgets(int)
+ * @param requestCode Code used to distinguish between different actions.
+ * @param bundle Optional bundle with additional information.
+ */
+ public void onDoAction(int requestCode, Bundle bundle) {
+
+ }
+
+ /**
+ * Called to notify a widget extension that it is no longer used and is
+ * being removed. The widget extension should clean up any resources it
+ * holds (threads, registered receivers, etc) at this point.
+ */
+ public void onDestroy() {
+
+ }
+
+ /**
+ * The widget has been touched. Override to handle touch events.
+ *
+ * @param type The type of touch event.
+ * @param x The x position of the touch event.
+ * @param y The y position of the touch event.
+ */
+ public void onTouch(final int type, final int x, final int y) {
+
+ }
+
+ /**
+ * Called when an object click event has occurred.
+ *
+ * @param type The type of click event
+ * @param layoutReference The referenced layout object
+ */
+ public void onObjectClick(final int type, final int layoutReference) {
+
+ }
+
+ /**
+ * Sends an image to the host application.
+ *
+ * @param resourceId The image resource id.
+ */
+ protected void sendImageToHostApp(final int resourceId) {
+ Intent intent = new Intent();
+ intent.setAction(Widget.Intents.WIDGET_IMAGE_UPDATE_INTENT);
+ BitmapDrawable bmd = (BitmapDrawable) mContext.getResources().getDrawable(resourceId);
+ ByteArrayOutputStream os = new ByteArrayOutputStream(256);
+ Bitmap bm = bmd.getBitmap();
+ bm.compress(CompressFormat.PNG, 100, os);
+ byte[] buffer = os.toByteArray();
+ intent.putExtra(Widget.Intents.EXTRA_WIDGET_IMAGE_DATA, buffer);
+
+ sendToHostApp(intent);
+ }
+
+ /**
+ * Send intent to host application. Adds host application package name and
+ * our package name.
+ *
+ * @param intent The intent to send.
+ */
+ protected void sendToHostApp(final Intent intent) {
+ intent.putExtra(Widget.Intents.EXTRA_AEA_PACKAGE_NAME, mContext.getPackageName());
+ intent.setPackage(mHostAppPackageName);
+ mContext.sendBroadcast(intent, Registration.HOSTAPP_PERMISSION);
+ }
+
+ /**
+ * Show bitmap on accessory.
+ *
+ * @param bitmap The bitmap to show.
+ */
+ protected void showBitmap(final Bitmap bitmap) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(256);
+ bitmap.compress(CompressFormat.PNG, 100, outputStream);
+
+ Intent intent = new Intent(Widget.Intents.WIDGET_IMAGE_UPDATE_INTENT);
+ intent.putExtra(Widget.Intents.EXTRA_WIDGET_IMAGE_DATA, outputStream.toByteArray());
+
+ sendToHostApp(intent);
+ }
+
+ /**
+ * Show a layout on the accessory.
+ *
+ * @param layoutId The layout resource id.
+ * @param layoutData The layout data.
+ */
+ protected void showLayout(final int layoutId) {
+ Intent intent = new Intent(Widget.Intents.WIDGET_PROCESS_LAYOUT_INTENT);
+ intent.putExtra(Widget.Intents.EXTRA_DATA_XML_LAYOUT, layoutId);
+ sendToHostApp(intent);
+ }
+
+ /**
+ * Update an image in a specific layout, on the accessory.
+ *
+ * @param layoutReference The referenced resource within the current layout.
+ * @param resourceId The image resource id.
+ */
+ protected void sendImage(final int layoutReference, final int resourceId) {
+ if (Dbg.DEBUG) {
+ Dbg.d("sendImage");
+ }
+
+ Intent intent = new Intent(Widget.Intents.WIDGET_SEND_IMAGE_INTENT);
+ intent.putExtra(Widget.Intents.EXTRA_LAYOUT_REFERENCE, layoutReference);
+ intent.putExtra(Widget.Intents.EXTRA_WIDGET_IMAGE_URI,
+ ExtensionUtils.getUriString(mContext, resourceId));
+ sendToHostApp(intent);
+ }
+
+ /**
+ * Update a TextView in a specific layout, on the accessory.
+ *
+ * @param layoutReference The referenced resource within the current layout.
+ * @param text The text to be updated.
+ */
+ protected void sendText(final int layoutReference, final String text) {
+ Intent intent = new Intent(Widget.Intents.WIDGET_SEND_TEXT_INTENT);
+ intent.putExtra(Widget.Intents.EXTRA_LAYOUT_REFERENCE, layoutReference);
+ intent.putExtra(Widget.Intents.EXTRA_WIDGET_TEXT, text);
+ sendToHostApp(intent);
+ }
+
+}
From cdd79e3f523241d7285f6a0e4837eb30854afbc4 Mon Sep 17 00:00:00 2001
From: Mike C