diff options
44 files changed, 803 insertions, 315 deletions
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 810e790..2df675e 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -237,8 +237,9 @@ public class AppWidgetManager { /** * Sent when the custom extras for an AppWidget change. * - * @see AppWidgetProvider#onAppWidgetExtrasChanged AppWidgetProvider#onAppWidgetExtrasChanged( - * Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras) + * @see AppWidgetProvider#onAppWidgetOptionsChanged + * AppWidgetProvider.onAppWidgetOptionsChanged(Context context, + * AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras) */ public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS"; diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip Binary files differindex e7e71f9..e48bfd3 100644 --- a/docs/downloads/training/BitmapFun.zip +++ b/docs/downloads/training/BitmapFun.zip diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd index db56fa4..485a1bb 100644 --- a/docs/html/about/versions/jelly-bean.jd +++ b/docs/html/about/versions/jelly-bean.jd @@ -1,29 +1,6 @@ page.title=Android 4.1 for Developers @jd:body - -<!--<style type="text/css"> -#jd-content { - max-width:1024px; -} -#jd-content div.screenshot { - float:left; - clear:left; - padding:15px 30px 15px 0; -} - -</style> - -<p></p> - - -<div style="float:right;width:230px;padding:0px 0px 60px 34px;margin-top:-40px"> -<div> -<img src="{@docRoot}images/android-jellybean-sm.png" xheight="402" width="280"> -</div> -<p class="image-caption">Find out more about the Jelly Bean features for users at <a href="http://www.android.com">android.com</a></p> -</div>--> - <div style="float:right;width:320px;padding:0px 0px 0px 34px;clear:both"> <div> <img src="{@docRoot}images/jb-android-4.1.png" height="426" width="390"> @@ -35,23 +12,9 @@ page.title=Android 4.1 for Developers improvements throughout the platform and added great new features for users and developers. This document provides a glimpse of what's new for developers. -<p>See the <a href="{@docRoot}about/versions/android-4.1.html">Android 4.1 APIs</a> document for a detailed look at the new developer APIs,</p> +<p>See the <a href="{@docRoot}about/versions/android-4.1.html">Android 4.1 APIs</a> document for a detailed look at the new developer APIs.</p> -<!-- -<ul> - <li><a href="#performance">Fast, Smooth, Responsive</a></li> - <li><a href="#accessibility">Enhanced Accessibility</a></li> - <li><a href="#intl">Support for International Users</a></li> - <li><a href="#ui">Capabilities for Creating Beautiful UI</a></li> - <li><a href="#input">New Input Types and Capabilities</a></li> - <li><a href="#graphics">Animation and Graphics</a></li> - <li><a href="#connectivity">New Types of Connectivity</a></li> - <li><a href="#media">Media Capabilities</a></li> - <li><a href="#google">Google APIs and services</a></li> - </ul> ---> - -<p>Find out more about the Jelly Bean features for users at <a href="http://www.android.com/whatsnew">www.android.com</a></p> +<p>Find out more about the Jelly Bean features for users at <a href="http://www.android.com/whatsnew">www.android.com</a>.</p> <h2 id="performance">Faster, Smoother, More Responsive</h2> diff --git a/docs/html/guide/google/gcm/adv.jd b/docs/html/guide/google/gcm/adv.jd index 2174128..aa66e25 100644 --- a/docs/html/guide/google/gcm/adv.jd +++ b/docs/html/guide/google/gcm/adv.jd @@ -51,7 +51,6 @@ delivered right away unless the <code>delay_while_idle</code> flag is set to tru <p>If the device is not connected to GCM, the message will be stored until a connection is established (again respecting the collapse key rules). When a connection is established, GCM will deliver all pending messages to the device, regardless of the <code>delay_while_idle</code> flag. If the device never gets connected again (for instance, if it was factory reset), the message will eventually time out and be discarded from GCM storage. The default timeout is 4 weeks, unless the <code>time_to_live</code> flag is set.</p> -<p class="note"><strong>Note:</strong> When you set the <code>time_to_live</code> flag, you must also set <code>collapse_key</code>. Otherwise the message will be rejected as a bad request.</p> <p>Finally, when GCM attempts to deliver a message to the device and the application was uninstalled, GCM will discard that message right away and invalidate the registration ID. Future attempts to send a message to that device will get a <code>NotRegistered</code> error. See <a href="#unreg">How Unregistration Works</a> for more information.</p> <p>Although is not possible to track the status of each individual message, the Google APIs Console stats are broken down by messages sent to device, messages collapsed, and messages waiting for delivery.</p> diff --git a/docs/html/guide/google/gcm/gcm.jd b/docs/html/guide/google/gcm/gcm.jd index 5515f31..c6f1a4e 100644 --- a/docs/html/guide/google/gcm/gcm.jd +++ b/docs/html/guide/google/gcm/gcm.jd @@ -57,9 +57,15 @@ page.title=GCM Architectural Overview </div> <p>Google Cloud Messaging for Android (GCM) is a free service that helps -developers send data from servers to their Android applications on Android devices. This could be a lightweight message telling the Android application that there is new data to be fetched from the server (for instance, a movie uploaded by a friend), or it could be a message containing up to 4kb of payload data (so apps like instant messaging can consume the message directly). The GCM service handles all aspects of queueing of - messages and delivery to the target Android application running on the target - device.</p> +developers send data from servers to their Android applications on Android +devices. This could be a lightweight message telling the Android application +that there is new data to be fetched from the server (for instance, a movie +uploaded by a friend), or it could be a message containing up to 4kb of payload +data (so apps like instant messaging can consume the message directly). The GCM +service handles all aspects of queueing of messages and delivery to the target +Android application running on the target device.</p> + + <p class="note"> To jump right into using GCM with your Android applications, see the instructions in <a href="gs.html">Getting Started</a>.</p> @@ -647,7 +653,7 @@ when the device is offline, so that only the last message gets sent to the client. This is intended to avoid sending too many messages to the phone when it comes back online. Note that since there is no guarantee of the order in which messages get sent, the "last" message may not actually be the last -message sent by the application server. See <a href="adv.html#collapsible">Advanced Topics</a> for more discussion of this topic. Optional, unless you are using the <code>time_to_live</code> parameter—in that case, you must also specify a <code>collapse_key</code>.</td> +message sent by the application server. See <a href="adv.html#collapsible">Advanced Topics</a> for more discussion of this topic. Optional.</td> </tr> <tr> <td><code>data</code></td> @@ -665,7 +671,7 @@ sent. Optional. The default value is <code>false</code>, and must be a JSON bool </tr> <tr> <td><code>time_to_live</code></td> - <td>How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number). If you use this parameter, you must also specify a <code>collapse_key</code>.</td> + <td>How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number).</td> </tr> </table> diff --git a/docs/html/guide/google/gcm/gs.jd b/docs/html/guide/google/gcm/gs.jd index 6f8598f..93eb794 100644 --- a/docs/html/guide/google/gcm/gs.jd +++ b/docs/html/guide/google/gcm/gs.jd @@ -138,8 +138,14 @@ page.title=GCM: Getting Started </ol> <p>This intent service will be called by the <code>GCMBroadcastReceiver</code> (which is is provided by GCM library), as shown in the next step. It must be a subclass of <code>com.google.android.gcm.GCMBaseIntentService</code>, must contain a public constructor, and should be named <code>my_app_package.GCMIntentService</code> (unless you use a subclass of <code>GCMBroadcastReceiver</code> that overrides the method used to name the service).</p> -<h4><br> - Step 3: Write the my_app_package.GCMIntentService class</h4> + +<p>The intent service must also define its sender ID(s). It does this as follows:</p> +<ul> + <li>If the value is static, the service's default constructor should call <code>super(senderIds)</code>.</li> + <li>If the value is dynamic, the service should override the <code>getSenderIds()</code> method.</li> +</ul> + +<h4>Step 3: Write the my_app_package.GCMIntentService class</h4> <p>Next write the <code>my_app_package.GCMIntentService</code> class, overriding the following callback methods (which are called by <code>GCMBroadcastReceiver</code>):<br> </p> <ul> diff --git a/docs/html/guide/google/gcm/server-javadoc/allclasses-frame.html b/docs/html/guide/google/gcm/server-javadoc/allclasses-frame.html index cf7dc28..80ee784 100644 --- a/docs/html/guide/google/gcm/server-javadoc/allclasses-frame.html +++ b/docs/html/guide/google/gcm/server-javadoc/allclasses-frame.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> All Classes </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/allclasses-noframe.html b/docs/html/guide/google/gcm/server-javadoc/allclasses-noframe.html index 299085c..966598d 100644 --- a/docs/html/guide/google/gcm/server-javadoc/allclasses-noframe.html +++ b/docs/html/guide/google/gcm/server-javadoc/allclasses-noframe.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> All Classes </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Constants.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Constants.html index 7384dfd..515bba4 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Constants.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Constants.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:09 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Constants </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/InvalidRequestException.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/InvalidRequestException.html index 56de783..bb0974c 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/InvalidRequestException.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/InvalidRequestException.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> InvalidRequestException </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.Builder.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.Builder.html index 7d5110c..c2ee648 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.Builder.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.Builder.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Message.Builder </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.html index 37a8a74..5dbd262 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Message.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Message </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/MulticastResult.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/MulticastResult.html index 21752ca..0721488 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/MulticastResult.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/MulticastResult.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> MulticastResult </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Result.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Result.html index 512b8f5..a4aad29 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Result.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Result.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Result </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Sender.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Sender.html index 5224e15..fabda98 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Sender.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/Sender.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Sender </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> @@ -591,6 +591,8 @@ protected static java.lang.String <B>getString</B>(java.io.InputStream stre <p> If the stream ends in a newline character, it will be stripped. + <p> + If the stream is null, returns an empty string. <P> <DD><DL> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-frame.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-frame.html index 9f099b3..1bc4fd9 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-frame.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-frame.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> com.google.android.gcm.server </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-summary.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-summary.html index eddcca1..de791c7 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-summary.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-summary.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> com.google.android.gcm.server </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-tree.html b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-tree.html index d3d1c43..d509312 100644 --- a/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-tree.html +++ b/docs/html/guide/google/gcm/server-javadoc/com/google/android/gcm/server/package-tree.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> com.google.android.gcm.server Class Hierarchy </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/constant-values.html b/docs/html/guide/google/gcm/server-javadoc/constant-values.html index 66df664..68db1cb 100644 --- a/docs/html/guide/google/gcm/server-javadoc/constant-values.html +++ b/docs/html/guide/google/gcm/server-javadoc/constant-values.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Constant Field Values </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/default.css b/docs/html/guide/google/gcm/server-javadoc/default.css index 2513e69..7c395c7 100644 --- a/docs/html/guide/google/gcm/server-javadoc/default.css +++ b/docs/html/guide/google/gcm/server-javadoc/default.css @@ -530,12 +530,12 @@ h3:target { } .design ol { counter-reset: item; } - .design ol li { + .design ol>li { font-size: 14px; line-height: 20px; list-style-type: none; position: relative; } - .design ol li:before { + .design ol>li:before { content: counter(item) ". "; counter-increment: item; position: absolute; @@ -561,16 +561,18 @@ h3:target { content: "9. "; } .design ol li.value-10:before { content: "10. "; } -.design .with-callouts ol li { +.design .with-callouts ol>li { list-style-position: inside; margin-left: 0; } - .design .with-callouts ol li:before { + .design .with-callouts ol>li:before { display: inline; left: -20px; float: left; width: 17px; color: #33b5e5; font-weight: 500; } +.design .with-callouts ul>li { + list-style-position: outside; } /* special list items */ li.no-bullet { @@ -1079,22 +1081,71 @@ color-stop(50%, #acbc00), color-stop(50%, #bdde00), color-stop(100%, #bdde00)); Print Only ========================================================================== */ @media print { -a { - color: inherit; -} -.nav-x, .nav-y { - display: none; -} -.str { color: #060; } -.kwd { color: #006; font-weight: bold; } -.com { color: #600; font-style: italic; } -.typ { color: #404; font-weight: bold; } -.lit { color: #044; } -.pun { color: #440; } -.pln { color: #000; } -.tag { color: #006; font-weight: bold; } -.atn { color: #404; } -.atv { color: #060; } + /* configure printed page */ + @page { + margin: 0.75in 1in; + widows: 4; + orphans: 4; + } + + /* reset spacing metrics */ + html, body, .wrap { + margin: 0 !important; + padding: 0 !important; + width: auto !important; + } + + /* leave enough space on the left for bullets */ + body { + padding-left: 20px !important; + } + #doc-col { + margin-left: 0; + } + + /* hide a bunch of non-content elements */ + #header, #footer, #nav-x, #side-nav, + .training-nav-top, .training-nav-bottom, + #doc-col .content-footer, + .nav-x, .nav-y, + .paging-links, + a.totop { + display: none !important; + } + + /* remove extra space above page titles */ + #doc-col .content-header { + margin-top: 0; + } + + /* bump up spacing above subheadings */ + h2 { + margin-top: 40px !important; + } + + /* print link URLs where possible and give links default text color */ + p a:after { + content: " (" attr(href) ")"; + font-size: 80%; + } + p a { + word-wrap: break-word; + } + a { + color: inherit; + } + + /* syntax highlighting rules */ + .str { color: #060; } + .kwd { color: #006; font-weight: bold; } + .com { color: #600; font-style: italic; } + .typ { color: #404; font-weight: bold; } + .lit { color: #044; } + .pun { color: #440; } + .pln { color: #000; } + .tag { color: #006; font-weight: bold; } + .atn { color: #404; } + .atv { color: #060; } } /* ============================================================================= @@ -2033,8 +2084,11 @@ div.toggle-content.closed .toggle-content-toggleme { #jd-content img.toggle-content-img { margin:0 5px 5px 0; } -div.toggle-content > p { - padding:0 0 5px; +div.toggle-content p { + margin:10px 0 0; +} +div.toggle-content-toggleme { + padding:0 0 0 15px; } @@ -2145,14 +2199,9 @@ table.blank th, table.blank td { .nolist { list-style:none; - padding:0; - margin:0 0 1em 1em; + margin-left:0; } -.nolist li { - padding:0 0 2px; - margin:0; -} pre.classic { background-color:transparent; @@ -2180,6 +2229,12 @@ p.table-caption { color:#666; } +div.note, +div.caution, +div.warning { + margin: 0 0 15px; +} + p.note, div.note, p.caution, div.caution, p.warning, div.warning { @@ -2898,10 +2953,6 @@ ul#search_filtered { /* SEARCH RESULTS */ -/* disable twiddle and size selectors for left column */ -#leftSearchControl div { - padding:0; -} #leftSearchControl .gsc-twiddle { background-image : none; @@ -3475,7 +3526,7 @@ EndColorStr='#ececec'); .morehover:hover { opacity:1; - height:345px; + height:385px; width:268px; -webkit-transition-property:height, -webkit-opacity; } @@ -3489,7 +3540,7 @@ EndColorStr='#ececec'); .morehover .mid { width:228px; background:url(../images/more_mid.png) repeat-y; - padding:10px 20px 10px 20px; + padding:10px 20px 0 20px; } .morehover .mid .header { @@ -3598,15 +3649,19 @@ a.download-sdk { padding-top: 14px; } +#nav-x .wrap { + min-height:34px; +} + #nav-x .wrap, #searchResults.wrap { max-width:940px; border-bottom:1px solid #CCC; - min-height:34px; - } - +#searchResults.wrap #leftSearchControl { + min-height:700px +} .nav-x { margin-left:0; margin-bottom:0; @@ -3762,7 +3817,8 @@ a.download-sdk { height: 300px; } .slideshow-develop img.play { - width:350px; + max-width:350px; + max-height:240px; margin:20px 0 0 90px; -webkit-transform: perspective(800px ) rotateY( 35deg ); box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3); @@ -3817,6 +3873,7 @@ a.download-sdk { .feed .feed-nav li { list-style: none; float: left; + height: 21px; /* +4px bottom border = 25px; same as .feed-nav */ margin-right: 25px; cursor: pointer; } @@ -3969,21 +4026,24 @@ a.download-sdk { .landing-docs { margin:20px 0 0; } -.landing-banner { - height:280px; -} .landing-banner .col-6:first-child, -.landing-docs .col-6:first-child { +.landing-docs .col-6:first-child, +.landing-docs .col-12 { margin-left:0; + min-height:280px; } .landing-banner .col-6:last-child, -.landing-docs .col-6:last-child { +.landing-docs .col-6:last-child, +.landing-docs .col-12 { margin-right:0; } .landing-banner h1 { margin-top:0; } +.landing-docs { + clear:left; +} .landing-docs h3 { font-size:14px; line-height:21px; @@ -4002,4 +4062,99 @@ a.download-sdk { .plusone { float:right; -}
\ No newline at end of file +} + + + +/************* HOME/LANDING PAGE *****************/ + +.slideshow-home { + height: 500px; + width: 940px; + border-bottom: 1px solid #CCC; + position: relative; + margin: 0; +} +.slideshow-home .frame { + width: 940px; + height: 500px; +} +.slideshow-home .content-left { + float: left; + text-align: center; + vertical-align: center; + margin: 0 0 0 35px; +} +.slideshow-home .content-right { + margin: 80px 0 0 0; +} +.slideshow-home .content-right p { + margin-bottom: 10px; +} +.slideshow-home .content-right p:last-child { + margin-top: 15px; +} +.slideshow-home .content-right h1 { + padding:0; +} +.slideshow-home .item { + height: 500px; + width: 940px; +} +.home-sections { + padding: 30px 20px 20px; + margin: 20px 0; + background: -webkit-linear-gradient(top, #F6F6F6,#F9F9F9); +} +.home-sections ul { + margin: 0; +} +.home-sections ul li { + float: left; + display: block; + list-style: none; + width: 170px; + height: 35px; + border: 1px solid #ccc; + background: white; + margin-right: 10px; + border-radius: 1px; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + box-shadow: 1px 1px 5px #EEE; + -webkit-box-shadow: 1px 1px 5px #EEE; + -moz-box-shadow: 1px 1px 5px #EEE; + background: white; +} +.home-sections ul li:hover { + background: #F9F9F9; + border: 1px solid #CCC; +} +.home-sections ul li a, +.home-sections ul li a:hover { + font-weight: bold; + margin-top: 8px; + line-height: 18px; + float: left; + width: 100%; + text-align: center; + color: #09c !important; +} +.home-sections ul li a { + font-weight: bold; + margin-top: 8px; + line-height: 18px; + float: left; + width:100%; + text-align:center; +} +.home-sections ul li img { + float: left; + margin: -8px 0 0 10px; +} +.home-sections ul li.last { + margin-right: 0px; +} +.fullpage #footer { + margin-top: -40px; +} diff --git a/docs/html/guide/google/gcm/server-javadoc/deprecated-list.html b/docs/html/guide/google/gcm/server-javadoc/deprecated-list.html index 729b2bf..04b9aa5 100644 --- a/docs/html/guide/google/gcm/server-javadoc/deprecated-list.html +++ b/docs/html/guide/google/gcm/server-javadoc/deprecated-list.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Deprecated List </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/help-doc.html b/docs/html/guide/google/gcm/server-javadoc/help-doc.html index 7f5286c..c479cff 100644 --- a/docs/html/guide/google/gcm/server-javadoc/help-doc.html +++ b/docs/html/guide/google/gcm/server-javadoc/help-doc.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> API Help </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/index-all.html b/docs/html/guide/google/gcm/server-javadoc/index-all.html index 0b095ec..97aa300 100644 --- a/docs/html/guide/google/gcm/server-javadoc/index-all.html +++ b/docs/html/guide/google/gcm/server-javadoc/index-all.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Index </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="./default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/index.html b/docs/html/guide/google/gcm/server-javadoc/index.html index d8ba0ef..d3c3821 100644 --- a/docs/html/guide/google/gcm/server-javadoc/index.html +++ b/docs/html/guide/google/gcm/server-javadoc/index.html @@ -2,7 +2,7 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc on Mon Jul 16 14:12:10 PDT 2012--> +<!-- Generated by javadoc on Wed Aug 29 14:55:34 PDT 2012--> <TITLE> Generated Documentation (Untitled) </TITLE> diff --git a/docs/html/guide/google/gcm/server-javadoc/overview-tree.html b/docs/html/guide/google/gcm/server-javadoc/overview-tree.html index b8e28ad..c9afea6 100644 --- a/docs/html/guide/google/gcm/server-javadoc/overview-tree.html +++ b/docs/html/guide/google/gcm/server-javadoc/overview-tree.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Class Hierarchy </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/gcm/server-javadoc/serialized-form.html b/docs/html/guide/google/gcm/server-javadoc/serialized-form.html index 7a1378f..ab99e41 100644 --- a/docs/html/guide/google/gcm/server-javadoc/serialized-form.html +++ b/docs/html/guide/google/gcm/server-javadoc/serialized-form.html @@ -2,12 +2,12 @@ <!--NewPage--> <HTML> <HEAD> -<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:12:10 PDT 2012 --> +<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 29 14:55:34 PDT 2012 --> <TITLE> Serialized Form </TITLE> -<META NAME="date" CONTENT="2012-07-16"> +<META NAME="date" CONTENT="2012-08-29"> <LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style"> diff --git a/docs/html/guide/google/play/publishing/multiple-apks.jd b/docs/html/guide/google/play/publishing/multiple-apks.jd index e41817e..0619dfc 100644 --- a/docs/html/guide/google/play/publishing/multiple-apks.jd +++ b/docs/html/guide/google/play/publishing/multiple-apks.jd @@ -9,9 +9,7 @@ page.title=Multiple APK Support <ul> <li>Simultaneously publish different APKs for different device configurations</li> - <li>Different APKs are distributed to different devices based on filters declared in the -manifest file</li> - <li>You should publish multiple APKs only when it's not possible or reasonable to + <li>You should publish multiple APKs only when it's not possible to support all desired devices with a single APK</li> </ul> @@ -39,16 +37,17 @@ support all desired devices with a single APK</li> <li><a href="#TextureOptions">Supporting multiple GL textures</a></li> <li><a href="#ScreenOptions">Supporting multiple screens</a></li> <li><a href="#ApiLevelOptions">Supporting multiple API levels</a></li> + <li><a href="#CpuArchOptions">Supporting multiple CPU architectures</a></li> </ol> </li> </ol> <h2>See also</h2> <ol> + <li><a href="{@docRoot}guide/google/play/expansion-files.html">APK Expansion Files</a></li> <li><a href="{@docRoot}guide/google/play/filters.html">Filters on Google Play</a></li> <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li> - <li><a href="{@docRoot}tools/extras/support-library.html">Compatibility -Package</a></li> + <li><a href="{@docRoot}tools/extras/support-library.html">Support Library</a></li> <li><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></li> </ol> @@ -76,14 +75,16 @@ many device configurations as possible, doing so is sometimes not possible. To h you publish your application for as many devices as possible, Google Play allows you to publish multiple APKs under the same application listing. Google Play then supplies each APK to the appropriate devices based on configuration support you've declared in the manifest file of each -APK.</p> +APK. </p> <p>By publishing your application with multiple APKs, you can:</p> <ul> <li>Support different OpenGL texture compression formats with each APK.</li> - <li>Support different screen configurations with each APK.</li> + <li>Support different screen sizes and densities with each APK.</li> <li>Support different platform versions with each APK.</li> + <li>Support different CPU architectures with each APK (such as for ARM, x86, and MIPS, when your + app uses the <a href="{@docRoot}tools/sdk/ndk/index.html">Android NDK</a>).</li> </ul> <p>Currently, these are the only device characteristics that Google Play supports for publishing @@ -91,7 +92,8 @@ multiple APKs as the same application.</p> <p class="note"><strong>Note:</strong> You should generally use multiple APKs to support different device configurations <strong>only when your APK is too large</strong> (greater than -50MB). Using a single APK to support different configurations is always the best practice, +50MB) due to the alternative resources needed for different device configurations. +Using a single APK to support different configurations is always the best practice, because it makes the path for application updates simple and clear for users (and also makes your life simpler by avoiding development and publishing complexity). Read the section below about <a href="#SingleAPK">Using a Single APK Instead</a> to @@ -283,14 +285,19 @@ higher, as per the previous note).</li> </ul> </div> </li> + + <li><strong>CPU architecture (ABI)</strong> + <p>This is based on the native libraries included in each APK (which are + determined by the architectures you declare in the {@code Application.mk} + file) when using the Android NDK.</p></li> </ul> <p>Other manifest elements that enable <a href="{@docRoot}guide/google/play/filters.html">Google Play filters</a>—but are not listed above—are still applied for each APK as usual. However, Google Play does not allow -you to publish multiple APKs based on variations of them. Thus, you cannot publish -multiple APKs if the above listed filters are the same for each APK (but the APKs differ based on -other characteristics in the manifest file). For +you to publish separate APKs based on variations of those device characteristics. Thus, you cannot +publish multiple APKs if the above listed filters are the same for each APK (but the APKs differ +based on other characteristics in the manifest or APK). For example, you cannot provide different APKs that differ purely on the <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">{@code <uses-configuration>}</a> characteristics.</p> @@ -349,7 +356,8 @@ greater. In this case, the API level is the only supported filter used, so the v get an update when they receive a system update.</li> <li>If you have one APK that's for API level 4 (and above) <em>and</em> small - large screens, and another APK for API level 8 (and above) <em>and</em> large - xlarge screens, then -the version codes <strong>must increase</strong>. In this case, the API level filter is used to +the version codes <strong>must increase</strong> in correlation with the API levels. +In this case, the API level filter is used to distinguish each APK, but so is the screen size. Because the screen sizes overlap (both APKs support large screens), the version codes must still be in order. This ensures that a large screen device that receives a system update to API level 8 will receive an update for the second @@ -360,6 +368,21 @@ screens, then the version codes <strong>do not need to increase</strong> in corr levels. Because there is no overlap within the screen size filter, there are no devices that could potentially move between these two APKs, so there's no need for the version codes to increase from the lower API level to the higher API level.</li> + <li>If you have one APK that's for API level 4 (and above) <em>and</em> ARMv7 CPUs, +and another APK for API level 8 (and above) <em>and</em> ARMv5TE CPUs, +then the version codes <strong>must increase</strong> in correlation with the API levels. +In this case, the API level filter is used to +distinguish each APK, but so is the CPU architecture. Because an APK with ARMv5TE libraries is +compatible with devices that have an ARMv7 CPU, the APKs overlap on this characteristic. +As such, the version code for the APK that supports API level 8 and above must be higher. +This ensures that a device with an ARMv7 CPU that receives a system update to API level 8 +will receive an update for the second APK that's designed for API level 8. +However, because this kind of update results in the ARMv7 device using an APK that's not +fully optimized for that device's CPU, you should provide an +APK for both the ARMv5TE and the ARMv7 architecture at each API level in order to optimize +the app performance on each CPU. +<strong>Note:</strong> This applies <em>only</em> when comparing APKs with the ARMv5TE and +ARMv7 libraries, and not when comparing other native libraries.</li> </ul> </li> @@ -384,7 +407,12 @@ screens so that all previously-supported devices are still supported.</li> sizes small, normal, and large, while another APK supports sizes large and xlarge, there is an overlap, because both APKs support large screens. If you do not resolve this, then devices that qualify for both APKs (large screen devices in the example) will receive whichever APK has the -highest version code.</li> +highest version code. + <p class="note"><strong>Note:</strong> If you're creating separate APKs for different CPU + architectures, be aware that an APK for ARMv5TE will overlap with an APK for ARMv7. That is, + an APK designed for ARMv5TE is compatible with an ARMv7 device, +but the reverse is not true (an APK with only the ARMv7 libraries is +<em>not</em> compatible with an ARMv5TE device).</li> </ul> <p>When such conflicts occur, you will see a warning message, but you can still publish your @@ -641,3 +669,17 @@ if (android.os.Build.VERSION.SDK_INT >= 11) { } </pre> + +<h3 id="CpuArchOptions">Supporting multiple CPU architectures</h3> + +<p>When using the Android NDK, you can create a single APK that supports multiple CPU architectures +by declaring each of the desired architectures with the {@code APP_ABI} variable in the +<code>Application.mk</code> file.</p> + +<p>For example, here's an <code>Application.mk</code> file that declares support for three +different CPU architectures:</p> + +<pre> +APP_ABI := armeabi armeabi-v7a mips +APP_PLATFORM := android-9 +</pre> diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd index a46f9a7..5a4e03a 100644 --- a/docs/html/guide/topics/appwidgets/index.jd +++ b/docs/html/guide/topics/appwidgets/index.jd @@ -307,6 +307,7 @@ following layout classes:</p> <li>{@link android.widget.FrameLayout}</li> <li>{@link android.widget.LinearLayout}</li> <li>{@link android.widget.RelativeLayout}</li> + <li>{@link android.widget.GridLayout}</li> </ul> <p>And the following widget classes:</p> @@ -327,6 +328,9 @@ following layout classes:</p> <p>Descendants of these classes are not supported.</p> +<p>RemoteViews also supports {@link android.view.ViewStub}, which is an invisible, zero-sized View you can use +to lazily inflate layout resources at runtime.</p> + <h3 id="AddingMargins">Adding margins to App Widgets</h3> @@ -410,6 +414,25 @@ App Widget, done. (See <a href="#Configuring">Creating an App Widget Configuration Activity</a> below.)</dd> + +<dt> + {@link android.appwidget.AppWidgetProvider#onAppWidgetOptionsChanged onAppWidgetOptionsChanged()} +</dt> +<dd> +This is called when the widget is first placed and any time the widget is resized. You can use this callback to show or hide content based on the widget's size ranges. You get the size ranges by calling {@link android.appwidget.AppWidgetManager#getAppWidgetOptions getAppWidgetOptions()}, which returns a {@link android.os.Bundle} that includes the following:<br /><br /> +<ul> + <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_WIDTH}—Contains +the lower bound on the current width, in dp units, of a widget instance.</li> + <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_HEIGHT}—Contains +the lower bound on the current height, in dp units, of a widget instance.</li> + <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_WIDTH}—Contains + the upper bound on the current width, in dp units, of a widget instance.</li> + <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_HEIGHT}—Contains +the upper bound on the current width, in dp units, of a widget instance.</li> +</ul> + +This callback was introduced in API Level 16 (Android 4.1). If you implement this callback, make sure that your app doesn't depend on it since it won't be called on older devices. +</dd> <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt> <dd>This is called every time an App Widget is deleted from the App Widget host.</dd> @@ -533,12 +556,13 @@ you would like to receive the App Widget broadcasts directly, you can implement your own {@link android.content.BroadcastReceiver} or override the {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. -The four Intents you need to care about are:</p> +The Intents you need to care about are as follows:</p> <ul> <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li> <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li> <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li> <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li> + <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_OPTIONS_CHANGED}</li> </ul> diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd index b0d5d6f..cf2c03e 100644 --- a/docs/html/guide/topics/resources/providing-resources.jd +++ b/docs/html/guide/topics/resources/providing-resources.jd @@ -548,6 +548,10 @@ which indicates the current device orientation.</p> no display</li> </ul> <p><em>Added in API level 8, television added in API 13.</em></p> + <p>For information about how your app can respond when the device is inserted into or + removed from a dock, read <a + href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Determining +and Monitoring the Docking State and Type</a>.</p> <p>This can change during the life of your application if the user places the device in a dock. You can enable or disable some of these modes using {@link android.app.UiModeManager}. See <a href="runtime-changes.html">Handling Runtime Changes</a> for diff --git a/docs/html/guide/topics/ui/themes.jd b/docs/html/guide/topics/ui/themes.jd index d787492..bc1c4f0 100644 --- a/docs/html/guide/topics/ui/themes.jd +++ b/docs/html/guide/topics/ui/themes.jd @@ -413,8 +413,8 @@ thoroughly describe the styles, so viewing the actual source code for these styl themes will give you a better understanding of what style properties each one provides. For a better reference to the Android styles and themes, see the following source code:</p> <ul> - <li><a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/res/res/values/styles.xml;h=d7b654e49809cb97a35682754b1394af5c8bc88b;hb=HEAD">Android Styles (styles.xml)</a></li> - <li><a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/res/res/values/themes.xml;h=6b3d7407d1c895a3c297e60d5beac98e2d34c271;hb=HEAD">Android Themes (themes.xml)</a></li> + <li><a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/styles.xml">Android Styles (styles.xml)</a></li> + <li><a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/themes.xml">Android Themes (themes.xml)</a></li> </ul> <p>These files will help you learn through example. For instance, in the Android themes source code, @@ -422,9 +422,8 @@ you'll find a declaration for <code><style name="Theme.Dialog"></code>. In you'll see all of the properties that are used to style dialogs that are used by the Android framework.</p> -<p>For more information about the syntax used to create styles in XML, see -<a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Available Resource Types: -Style and Themes</a>.</p> +<p>For more information about the syntax for styles and themes in XML, see the +<a href="{@docRoot}guide/topics/resources/style-resource.html">Style Resource</a> document.</p> <p>For a reference of available style attributes that you can use to define a style or theme (e.g., "windowBackground" or "textAppearance"), see {@link android.R.attr} or the respective diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd index 4fc2ca6..feec56d 100644 --- a/docs/html/sdk/installing/installing-adt.jd +++ b/docs/html/sdk/installing/installing-adt.jd @@ -63,23 +63,20 @@ the software can't be established, click <strong>OK</strong>.</p></li> <h2 id="Configure">Configure the ADT Plugin</h2> -<p>After you've installed ADT and restarted Eclipse, you +<p>Once Eclipse restarts, you must specify the location of your Android SDK directory:</p> <ol> - <li>Select <strong>Window</strong> > <strong>Preferences...</strong> to open the Preferences - panel (on Mac OS X, select <strong>Eclipse</strong> > <strong>Preferences</strong>).</li> - <li>Select <strong>Android</strong> from the left panel.</li> - <p>You may see a dialog asking whether you want to send usage statistics to Google. If so, -make your choice and click <strong>Proceed</strong>.</p> - <li>For the <em>SDK Location</em> in the main panel, click <strong>Browse...</strong> and - locate your downloaded Android SDK directory (such as <code>android-sdk-windows</code>).</li> - <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li> + <li>In the "Welcome to Android Development" window that appears, select <strong>Use +existing SDKs</strong>.</li> + <li>Browse and select the location of the Android SDK directory you recently +downloaded.</li> + <li>Click <strong>Next</strong>.</li> </ol> <p>If you haven't encountered any errors, you're done setting up ADT - and can continue to the next step of the SDK installation.</p> + and can continue to <a href="{@docRoot}sdk/installing/next.html">Next Steps</a>.</p> diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd index 94abe21..2a333cc 100644 --- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd +++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd @@ -96,7 +96,7 @@ and leave the rest of your app little memory to work with.</p> <p>Here’s an example of setting up a {@link android.util.LruCache} for bitmaps:</p> <pre> -private LruCache<String, Bitmap> mMemoryCache; +private LruCache<String, Bitmap> mMemoryCache; @Override protected void onCreate(Bundle savedInstanceState) { @@ -109,7 +109,7 @@ protected void onCreate(Bundle savedInstanceState) { // Use 1/8th of the available memory for this memory cache. final int cacheSize = 1024 * 1024 * memClass / 8; - mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { + mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than number of items. @@ -159,7 +159,7 @@ public void loadBitmap(int resId, ImageView imageView) { updated to add entries to the memory cache:</p> <pre> -class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { +class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { ... // Decode image in background. @Override @@ -179,7 +179,7 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { rely on images being available in this cache. Components like {@link android.widget.GridView} with larger datasets can easily fill up a memory cache. Your application could be interrupted by another task like a phone call, and while in the background it might be killed and the memory cache -destroyed. Once the user resumes, your application it has to process each image again.</p> +destroyed. Once the user resumes, your application has to process each image again.</p> <p>A disk cache can be used in these cases to persist processed bitmaps and help decrease loading times where images are no longer available in a memory cache. Of course, fetching images from disk @@ -190,18 +190,14 @@ be unpredictable.</p> appropriate place to store cached images if they are accessed more frequently, for example in an image gallery application.</p> -<p>Included in the sample code of this class is a basic {@code DiskLruCache} implementation. -However, a more robust and recommended {@code DiskLruCache} solution is included in the Android 4.0 -source code ({@code libcore/luni/src/main/java/libcore/io/DiskLruCache.java}). Back-porting this -class for use on previous Android releases should be fairly straightforward (a <a -href="http://www.google.com/search?q=disklrucache">quick search</a> shows others who have already -implemented this solution).</p> - -<p>Here’s updated example code that uses the simple {@code DiskLruCache} included in the sample -application of this class:</p> +<p>The sample code of this class uses a {@code DiskLruCache} implementation that is pulled from the +<a href="https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>. Here’s updated example code that adds a disk cache in addition +to the existing memory cache:</p> <pre> -private DiskLruCache mDiskCache; +private DiskLruCache mDiskLruCache; +private final Object mDiskCacheLock = new Object(); +private boolean mDiskCacheStarting = true; private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB private static final String DISK_CACHE_SUBDIR = "thumbnails"; @@ -210,12 +206,26 @@ protected void onCreate(Bundle savedInstanceState) { ... // Initialize memory cache ... - File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR); - mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE); + // Initialize disk cache on background thread + File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR); + new InitDiskCacheTask().execute(cacheDir); ... } -class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { +class InitDiskCacheTask extends AsyncTask<File, Void, Void> { + @Override + protected Void doInBackground(File... params) { + synchronized (mDiskCacheLock) { + File cacheDir = params[0]; + mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE); + mDiskCacheStarting = false; // Finished initialization + mDiskCacheLock.notifyAll(); // Wake any waiting threads + } + return null; + } +} + +class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { ... // Decode image in background. @Override @@ -232,7 +242,7 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { } // Add final bitmap to caches - addBitmapToCache(String.valueOf(imageKey, bitmap); + addBitmapToCache(imageKey, bitmap); return bitmap; } @@ -246,28 +256,48 @@ public void addBitmapToCache(String key, Bitmap bitmap) { } // Also add to disk cache - if (!mDiskCache.containsKey(key)) { - mDiskCache.put(key, bitmap); + synchronized (mDiskCacheLock) { + if (mDiskLruCache != null && mDiskLruCache.get(key) == null) { + mDiskLruCache.put(key, bitmap); + } } } public Bitmap getBitmapFromDiskCache(String key) { - return mDiskCache.get(key); + synchronized (mDiskCacheLock) { + // Wait while disk cache is started from background thread + while (mDiskCacheStarting) { + try { + mDiskCacheLock.wait(); + } catch (InterruptedException e) {} + } + if (mDiskLruCache != null) { + return mDiskLruCache.get(key); + } + } + return null; } // Creates a unique subdirectory of the designated app cache directory. Tries to use external // but if not mounted, falls back on internal storage. -public static File getCacheDir(Context context, String uniqueName) { +public static File getDiskCacheDir(Context context, String uniqueName) { // Check if media is mounted or storage is built-in, if so, try and use external cache dir // otherwise use internal cache dir - final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED - || !Environment.isExternalStorageRemovable() ? - context.getExternalCacheDir().getPath() : context.getCacheDir().getPath(); + final String cachePath = + Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || + !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() : + context.getCacheDir().getPath(); return new File(cachePath + File.separator + uniqueName); } </pre> +<p class="note"><strong>Note:</strong> Even initializing the disk cache requires disk operations +and therefore should not take place on the main thread. However, this does mean there's a chance +the cache is accessed before initialization. To address this, in the above implementation, a lock +object ensures that the app does not read from the disk cache until the cache has been +initialized.</p> + <p>While the memory cache is checked in the UI thread, the disk cache is checked in the background thread. Disk operations should never take place on the UI thread. When image processing is complete, the final bitmap is added to both the memory and disk cache for future use.</p> @@ -292,7 +322,7 @@ android.widget.ImageView} objects.</p> changes using a {@link android.app.Fragment}:</p> <pre> -private LruCache<String, Bitmap> mMemoryCache; +private LruCache<String, Bitmap> mMemoryCache; @Override protected void onCreate(Bundle savedInstanceState) { @@ -301,7 +331,7 @@ protected void onCreate(Bundle savedInstanceState) { RetainFragment.findOrCreateRetainFragment(getFragmentManager()); mMemoryCache = RetainFragment.mRetainedCache; if (mMemoryCache == null) { - mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { + mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { ... // Initialize cache here as usual } mRetainFragment.mRetainedCache = mMemoryCache; @@ -311,7 +341,7 @@ protected void onCreate(Bundle savedInstanceState) { class RetainFragment extends Fragment { private static final String TAG = "RetainFragment"; - public LruCache<String, Bitmap> mRetainedCache; + public LruCache<String, Bitmap> mRetainedCache; public RetainFragment() {} diff --git a/docs/html/training/displaying-bitmaps/display-bitmap.jd b/docs/html/training/displaying-bitmaps/display-bitmap.jd index 5eac04c..4572c42 100644 --- a/docs/html/training/displaying-bitmaps/display-bitmap.jd +++ b/docs/html/training/displaying-bitmaps/display-bitmap.jd @@ -103,7 +103,8 @@ public class ImageDetailActivity extends FragmentActivity { } </pre> -<p>The details {@link android.app.Fragment} holds the {@link android.widget.ImageView} children:</p> +<p>Here is an implementation of the details {@link android.app.Fragment} which holds the {@link android.widget.ImageView} children. This might seem like a perfectly reasonable approach, but can +you see the drawbacks of this implementation? How could it be improved?</p> <pre> public class ImageDetailFragment extends Fragment { @@ -146,11 +147,11 @@ public class ImageDetailFragment extends Fragment { } </pre> -<p>Hopefully you noticed the issue with this implementation; The images are being read from -resources on the UI thread which can lead to an application hanging and being force closed. Using an -{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps Off -the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a background -thread:</p> +<p>Hopefully you noticed the issue: the images are being read from resources on the UI thread, +which can lead to an application hanging and being force closed. Using an +{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps +Off the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a +background thread:</p> <pre> public class ImageDetailActivity extends FragmentActivity { @@ -190,7 +191,7 @@ modifications for a memory cache:</p> <pre> public class ImageDetailActivity extends FragmentActivity { ... - private LruCache<String, Bitmap> mMemoryCache; + private LruCache<String, Bitmap> mMemoryCache; @Override public void onCreate(Bundle savedInstanceState) { @@ -229,7 +230,8 @@ UI remains fluid, memory usage remains under control and concurrency is handled the way {@link android.widget.GridView} recycles its children views).</p> <p>To start with, here is a standard {@link android.widget.GridView} implementation with {@link -android.widget.ImageView} children placed inside a {@link android.app.Fragment}:</p> +android.widget.ImageView} children placed inside a {@link android.app.Fragment}. Again, this might +seem like a perfectly reasonable approach, but what would make it better?</p> <pre> public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener { @@ -261,7 +263,7 @@ public class ImageGridFragment extends Fragment implements AdapterView.OnItemCli } @Override - public void onItemClick(AdapterView<?> parent, View v, int position, long id) { + public void onItemClick(AdapterView<?> parent, View v, int position, long id) { final Intent i = new Intent(getActivity(), ImageDetailActivity.class); i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position); startActivity(i); @@ -345,13 +347,13 @@ public class ImageGridFragment extends Fragment implements AdapterView.OnItemCli } static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = - new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); + new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd index 78371ad..b91172b 100644 --- a/docs/html/training/displaying-bitmaps/index.jd +++ b/docs/html/training/displaying-bitmaps/index.jd @@ -43,8 +43,8 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget perform under this minimum memory limit. However, keep in mind many devices are configured with higher limits.</li> <li>Bitmaps take up a lot of memory, especially for rich images like photographs. For example, the - camera on the <a href="http://www.google.com/nexus/">Galaxy Nexus</a> takes photos up to 2592x1936 - pixels (5 megapixels). If the bitmap configuration used is {@link + camera on the <a href="http://www.android.com/devices/detail/galaxy-nexus">Galaxy Nexus</a> takes + photos up to 2592x1936 pixels (5 megapixels). If the bitmap configuration used is {@link android.graphics.Bitmap.Config ARGB_8888} (the default from the Android 2.3 onward) then loading this image into memory takes about 19MB of memory (2592*1936*4 bytes), immediately exhausting the per-app limit on some devices.</li> @@ -75,4 +75,4 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView} using a background thread and bitmap cache.</dd> -</dl>
\ No newline at end of file +</dl> diff --git a/docs/html/training/displaying-bitmaps/process-bitmap.jd b/docs/html/training/displaying-bitmaps/process-bitmap.jd index d1e346c..d4fcff3 100644 --- a/docs/html/training/displaying-bitmaps/process-bitmap.jd +++ b/docs/html/training/displaying-bitmaps/process-bitmap.jd @@ -62,13 +62,13 @@ decodeSampledBitmapFromResource()}</a>: </p> <a name="BitmapWorkerTask"></a> <pre> -class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; +class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { + private final WeakReference<ImageView> imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected - imageViewReference = new WeakReference<ImageView>(imageView); + imageViewReference = new WeakReference<ImageView>(imageView); } // Decode image in background. @@ -133,13 +133,13 @@ completes:</p> <a name="AsyncDrawable"></a> <pre> static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = - new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); + new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { @@ -211,7 +211,7 @@ one associated with the {@link android.widget.ImageView}:</p> <a name="BitmapWorkerTaskUpdated"></a> <pre> -class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { +class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { ... @Override @@ -236,4 +236,4 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { android.widget.GridView} components as well as any other components that recycle their child views. Simply call {@code loadBitmap} where you normally set an image to your {@link android.widget.ImageView}. For example, in a {@link android.widget.GridView} implementation this -would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p>
\ No newline at end of file +would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 5841978..17dbcac 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -67,7 +67,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fadingEdge="none" - android:overScrollMode="always" + android:overScrollMode="ifContentScrolls" > <com.android.systemui.statusbar.policy.NotificationRowLayout android:id="@+id/latestItems" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 26dba67..fd5ef4e 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -65,5 +65,8 @@ <!-- Vibration duration for MultiWaveView used in SearchPanelView --> <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer> + + <!-- The length of the vibration when the notificaiotn pops open. --> + <integer name="blinds_pop_duration_ms">10</integer> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 6c40461..c6fd66a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -150,4 +150,10 @@ <!-- Height of the carrier/wifi name label --> <dimen name="carrier_label_height">24dp</dimen> + + <!-- The distance you can pull a notificaiton before it pops open --> + <dimen name="blinds_pop_threshold">32dp</dimen> + + <!-- The size of the gesture span needed to activate the "pull" notification expansion --> + <dimen name="pull_span_min">25dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 8ebbc52..4a73200 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -18,4 +18,5 @@ <resources> <item type="id" name="expandable_tag" /> <item type="id" name="user_expanded_tag" /> + <item type="id" name="user_lock_tag" /> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index 5dd15c3..dcfd0b3 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -22,28 +22,35 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; +import android.os.Vibrator; import android.util.Slog; import android.view.Gravity; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.View.OnClickListener; +import java.util.Stack; + public class ExpandHelper implements Gefingerpoken, OnClickListener { public interface Callback { View getChildAtRawPosition(float x, float y); View getChildAtPosition(float x, float y); boolean canChildBeExpanded(View v); - boolean setUserExpandedChild(View v, boolean userxpanded); + boolean setUserExpandedChild(View v, boolean userExpanded); + boolean setUserLockedChild(View v, boolean userLocked); } private static final String TAG = "ExpandHelper"; protected static final boolean DEBUG = false; + protected static final boolean DEBUG_SCALE = false; + protected static final boolean DEBUG_GLOW = false; private static final long EXPAND_DURATION = 250; private static final long GLOW_DURATION = 150; - // Set to false to disable focus-based gestures (two-finger pull). + // Set to false to disable focus-based gestures (spread-finger vertical pull). private static final boolean USE_DRAG = true; // Set to false to disable scale-based gestures (both horizontal and vertical). private static final boolean USE_SPAN = true; @@ -62,7 +69,14 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { @SuppressWarnings("unused") private Context mContext; - private boolean mStretching; + private boolean mExpanding; + private static final int NONE = 0; + private static final int BLINDS = 1<<0; + private static final int PULL = 1<<1; + private static final int STRETCH = 1<<2; + private int mExpansionStyle = NONE; + private boolean mWatchingForPull; + private boolean mHasPopped; private View mEventSource; private View mCurrView; private View mCurrViewTopGlow; @@ -70,14 +84,21 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private float mOldHeight; private float mNaturalHeight; private float mInitialTouchFocusY; + private float mInitialTouchY; private float mInitialTouchSpan; + private int mTouchSlop; + private int mLastMotionY; + private float mPopLimit; + private int mPopDuration; + private float mPullGestureMinXSpan; private Callback mCallback; - private ScaleGestureDetector mDetector; + private ScaleGestureDetector mSGD; private ViewScaler mScaler; private ObjectAnimator mScaleAnimation; private AnimatorSet mGlowAnimationSet; private ObjectAnimator mGlowTopAnimation; private ObjectAnimator mGlowBottomAnimation; + private Vibrator mVibrator; private int mSmallSize; private int mLargeSize; @@ -85,6 +106,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private int mGravity; + private View mScrollView; + private class ViewScaler { View mView; @@ -93,7 +116,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mView = v; } public void setHeight(float h) { - if (DEBUG) Slog.v(TAG, "SetHeight: setting to " + h); + if (DEBUG_SCALE) Slog.v(TAG, "SetHeight: setting to " + h); ViewGroup.LayoutParams lp = mView.getLayoutParams(); lp.height = (int)h; mView.setLayoutParams(lp); @@ -104,11 +127,12 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (height < 0) { height = mView.getMeasuredHeight(); } - return (float) height; + return height; } public int getNaturalHeight(int maximum) { ViewGroup.LayoutParams lp = mView.getLayoutParams(); - if (DEBUG) Slog.v(TAG, "Inspecting a child of type: " + mView.getClass().getName()); + if (DEBUG_SCALE) Slog.v(TAG, "Inspecting a child of type: " + + mView.getClass().getName()); int oldHeight = lp.height; lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; mView.setLayoutParams(lp); @@ -142,6 +166,9 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mGravity = Gravity.TOP; mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f); mScaleAnimation.setDuration(EXPAND_DURATION); + mPopLimit = mContext.getResources().getDimension(R.dimen.blinds_pop_threshold); + mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms); + mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min); AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() { @Override @@ -169,74 +196,108 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation); mGlowAnimationSet.setDuration(GLOW_DURATION); - mDetector = - new ScaleGestureDetector(context, + final ViewConfiguration configuration = ViewConfiguration.get(mContext); + mTouchSlop = configuration.getScaledTouchSlop(); + + mSGD = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { - if (DEBUG) Slog.v(TAG, "onscalebegin()"); - float x = detector.getFocusX(); - float y = detector.getFocusY(); - - View v = null; - if (mEventSource != null) { - int[] location = new int[2]; - mEventSource.getLocationOnScreen(location); - x += (float) location[0]; - y += (float) location[1]; - v = mCallback.getChildAtRawPosition(x, y); - } else { - v = mCallback.getChildAtPosition(x, y); - } + if (DEBUG_SCALE) Slog.v(TAG, "onscalebegin()"); + float focusX = detector.getFocusX(); + float focusY = detector.getFocusY(); // your fingers have to be somewhat close to the bounds of the view in question - mInitialTouchFocusY = detector.getFocusY(); + mInitialTouchFocusY = focusY; mInitialTouchSpan = Math.abs(detector.getCurrentSpan()); - if (DEBUG) Slog.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")"); + if (DEBUG_SCALE) Slog.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")"); - mStretching = initScale(v); - return mStretching; + final View underFocus = findView(focusX, focusY); + if (underFocus != null) { + startExpanding(underFocus, STRETCH); + } + return mExpanding; } @Override public boolean onScale(ScaleGestureDetector detector) { - if (DEBUG) Slog.v(TAG, "onscale() on " + mCurrView); - - // are we scaling or dragging? - float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan; - span *= USE_SPAN ? 1f : 0f; - float drag = detector.getFocusY() - mInitialTouchFocusY; - drag *= USE_DRAG ? 1f : 0f; - drag *= mGravity == Gravity.BOTTOM ? -1f : 1f; - float pull = Math.abs(drag) + Math.abs(span) + 1f; - float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull; - if (DEBUG) Slog.d(TAG, "current span handle is: " + hand); - hand = hand + mOldHeight; - float target = hand; - if (DEBUG) Slog.d(TAG, "target is: " + target); - hand = hand < mSmallSize ? mSmallSize : (hand > mLargeSize ? mLargeSize : hand); - hand = hand > mNaturalHeight ? mNaturalHeight : hand; - if (DEBUG) Slog.d(TAG, "scale continues: hand =" + hand); - mScaler.setHeight(hand); - - // glow if overscale - float stretch = (float) Math.abs((target - hand) / mMaximumStretch); - float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f))); - if (DEBUG) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength); - setGlow(GLOW_BASE + strength * (1f - GLOW_BASE)); + if (DEBUG_SCALE) Slog.v(TAG, "onscale() on " + mCurrView); + updateExpansion(); return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { - if (DEBUG) Slog.v(TAG, "onscaleend()"); + if (DEBUG_SCALE) Slog.v(TAG, "onscaleend()"); // I guess we're alone now - if (DEBUG) Slog.d(TAG, "scale end"); - finishScale(false); + if (DEBUG_SCALE) Slog.d(TAG, "scale end"); + finishExpanding(false); + clearView(); } }); } + private void updateExpansion() { + // are we scaling or dragging? + float span = Math.abs(mSGD.getCurrentSpan()) - mInitialTouchSpan; + span *= USE_SPAN ? 1f : 0f; + float drag = mSGD.getFocusY() - mInitialTouchFocusY; + drag *= USE_DRAG ? 1f : 0f; + drag *= mGravity == Gravity.BOTTOM ? -1f : 1f; + float pull = Math.abs(drag) + Math.abs(span) + 1f; + float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull; + float target = hand + mOldHeight; + float newHeight = clamp(target); + mScaler.setHeight(newHeight); + + setGlow(calculateGlow(target, newHeight)); + } + + private float clamp(float target) { + float out = target; + out = out < mSmallSize ? mSmallSize : (out > mLargeSize ? mLargeSize : out); + out = out > mNaturalHeight ? mNaturalHeight : out; + return out; + } + + private View findView(float x, float y) { + View v = null; + if (mEventSource != null) { + int[] location = new int[2]; + mEventSource.getLocationOnScreen(location); + x += location[0]; + y += location[1]; + v = mCallback.getChildAtRawPosition(x, y); + } else { + v = mCallback.getChildAtPosition(x, y); + } + return v; + } + + private boolean isInside(View v, float x, float y) { + if (DEBUG) Slog.d(TAG, "isinside (" + x + ", " + y + ")"); + + if (v == null) { + if (DEBUG) Slog.d(TAG, "isinside null subject"); + return false; + } + if (mEventSource != null) { + int[] location = new int[2]; + mEventSource.getLocationOnScreen(location); + x += location[0]; + y += location[1]; + if (DEBUG) Slog.d(TAG, " to global (" + x + ", " + y + ")"); + } + int[] location = new int[2]; + v.getLocationOnScreen(location); + x -= location[0]; + y -= location[1]; + if (DEBUG) Slog.d(TAG, " to local (" + x + ", " + y + ")"); + if (DEBUG) Slog.d(TAG, " inside (" + v.getWidth() + ", " + v.getHeight() + ")"); + boolean inside = (x > 0f && y > 0f && x < v.getWidth() & y < v.getHeight()); + return inside; + } + public void setEventSource(View eventSource) { mEventSource = eventSource; } @@ -245,13 +306,26 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mGravity = gravity; } + public void setScrollView(View scrollView) { + mScrollView = scrollView; + } + + private float calculateGlow(float target, float actual) { + // glow if overscale + if (DEBUG_GLOW) Slog.d(TAG, "target: " + target + " actual: " + actual); + float stretch = Math.abs((target - actual) / mMaximumStretch); + float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f))); + if (DEBUG_GLOW) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength); + return (GLOW_BASE + strength * (1f - GLOW_BASE)); + } + public void setGlow(float glow) { if (!mGlowAnimationSet.isRunning() || glow == 0f) { if (mGlowAnimationSet.isRunning()) { - mGlowAnimationSet.cancel(); + mGlowAnimationSet.end(); } if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) { - if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) { + if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) { // animate glow in and out mGlowTopAnimation.setTarget(mCurrViewTopGlow); mGlowBottomAnimation.setTarget(mCurrViewBottomGlow); @@ -276,72 +350,196 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { View.INVISIBLE : View.VISIBLE); } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (DEBUG) Slog.d(TAG, "interceptTouch: act=" + (ev.getAction()) + - " stretching=" + mStretching); - mDetector.onTouchEvent(ev); - return mStretching; + final int action = ev.getAction(); + if (DEBUG_SCALE) Slog.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) + + " expanding=" + mExpanding + + (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") + + (0 != (mExpansionStyle & PULL) ? " (pull)" : "") + + (0 != (mExpansionStyle & STRETCH) ? " (stretch)" : "")); + // check for a spread-finger vertical pull gesture + mSGD.onTouchEvent(ev); + final int x = (int) mSGD.getFocusX(); + final int y = (int) mSGD.getFocusY(); + if (mExpanding) { + return true; + } else { + if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) { + // we've begun Venetian blinds style expansion + return true; + } + final float xspan = mSGD.getCurrentSpanX(); + if ((action == MotionEvent.ACTION_MOVE && + xspan > mPullGestureMinXSpan && + xspan > mSGD.getCurrentSpanY())) { + // detect a vertical pulling gesture with fingers somewhat separated + if (DEBUG_SCALE) Slog.v(TAG, "got pull gesture (xspan=" + xspan + "px)"); + + mInitialTouchFocusY = y; + + final View underFocus = findView(x, y); + if (underFocus != null) { + startExpanding(underFocus, PULL); + } + return true; + } + if (mScrollView != null && mScrollView.getScrollY() > 0) { + return false; + } + // Now look for other gestures + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_MOVE: { + if (mWatchingForPull) { + final int yDiff = y - mLastMotionY; + if (yDiff > mTouchSlop) { + if (DEBUG) Slog.v(TAG, "got venetian gesture (dy=" + yDiff + "px)"); + mLastMotionY = y; + final View underFocus = findView(x, y); + if (underFocus != null) { + startExpanding(underFocus, BLINDS); + mInitialTouchY = mLastMotionY; + mHasPopped = false; + } + } + } + break; + } + + case MotionEvent.ACTION_DOWN: + mWatchingForPull = isInside(mScrollView, x, y); + mLastMotionY = y; + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (DEBUG) Slog.d(TAG, "up/cancel"); + finishExpanding(false); + clearView(); + break; + } + return mExpanding; + } } + @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); - if (DEBUG) Slog.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching); - if (mStretching) { - if (DEBUG) Slog.d(TAG, "detector ontouch"); - mDetector.onTouchEvent(ev); - } + if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + MotionEvent.actionToString(action) + + " expanding=" + mExpanding + + (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") + + (0 != (mExpansionStyle & PULL) ? " (pull)" : "") + + (0 != (mExpansionStyle & STRETCH) ? " (stretch)" : "")); + + mSGD.onTouchEvent(ev); + switch (action) { + case MotionEvent.ACTION_MOVE: { + if (0 != (mExpansionStyle & BLINDS)) { + final float rawHeight = ev.getY() - mInitialTouchY + mOldHeight; + final float newHeight = clamp(rawHeight); + final boolean wasClosed = (mOldHeight == mSmallSize); + boolean isFinished = false; + if (rawHeight > mNaturalHeight) { + isFinished = true; + } + if (rawHeight < mSmallSize) { + isFinished = true; + } + + final float pull = Math.abs(ev.getY() - mInitialTouchY); + if (mHasPopped || pull > mPopLimit) { + if (!mHasPopped) { + vibrate(mPopDuration); + mHasPopped = true; + } + } + + if (mHasPopped) { + mScaler.setHeight(newHeight); + setGlow(GLOW_BASE); + } else { + setGlow(calculateGlow(4f * pull, 0f)); + } + + final int x = (int) mSGD.getFocusX(); + final int y = (int) mSGD.getFocusY(); + View underFocus = findView(x, y); + if (isFinished && underFocus != null && underFocus != mCurrView) { + finishExpanding(false); // @@@ needed? + startExpanding(underFocus, BLINDS); + mInitialTouchY = y; + mHasPopped = false; + } + return true; + } + + if (mExpanding) { + updateExpansion(); + return true; + } + + break; + } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (DEBUG) Slog.d(TAG, "cancel"); - mStretching = false; + if (DEBUG) Slog.d(TAG, "up/cancel"); + finishExpanding(false); clearView(); break; } return true; } - private boolean initScale(View v) { - if (v != null) { - if (DEBUG) Slog.d(TAG, "scale begins on view: " + v); - mStretching = true; - setView(v); - setGlow(GLOW_BASE); - mScaler.setView(v); - mOldHeight = mScaler.getHeight(); - if (mCallback.canChildBeExpanded(v)) { - if (DEBUG) Slog.d(TAG, "working on an expandable child"); - mNaturalHeight = mScaler.getNaturalHeight(mLargeSize); - } else { - if (DEBUG) Slog.d(TAG, "working on a non-expandable child"); - mNaturalHeight = mOldHeight; - } - if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight + - " mNaturalHeight: " + mNaturalHeight); - v.getParent().requestDisallowInterceptTouchEvent(true); + + private void startExpanding(View v, int expandType) { + mExpanding = true; + mExpansionStyle = expandType; + if (DEBUG) Slog.d(TAG, "scale type " + expandType + " beginning on view: " + v); + mCallback.setUserLockedChild(v, true); + setView(v); + setGlow(GLOW_BASE); + mScaler.setView(v); + mOldHeight = mScaler.getHeight(); + if (mCallback.canChildBeExpanded(v)) { + if (DEBUG) Slog.d(TAG, "working on an expandable child"); + mNaturalHeight = mScaler.getNaturalHeight(mLargeSize); + } else { + if (DEBUG) Slog.d(TAG, "working on a non-expandable child"); + mNaturalHeight = mOldHeight; } - return mStretching; + if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight + + " mNaturalHeight: " + mNaturalHeight); + v.getParent().requestDisallowInterceptTouchEvent(true); } - private void finishScale(boolean force) { + private void finishExpanding(boolean force) { + if (!mExpanding) return; + + float currentHeight = mScaler.getHeight(); + float targetHeight = mSmallSize; float h = mScaler.getHeight(); final boolean wasClosed = (mOldHeight == mSmallSize); if (wasClosed) { - h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize; + targetHeight = (force || currentHeight > mSmallSize) ? mNaturalHeight : mSmallSize; } else { - h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight; + targetHeight = (force || currentHeight < mNaturalHeight) ? mSmallSize : mNaturalHeight; } - if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0); if (mScaleAnimation.isRunning()) { mScaleAnimation.cancel(); } - mScaleAnimation.setFloatValues(h); - mScaleAnimation.setupStartValues(); - mScaleAnimation.start(); - mStretching = false; setGlow(0f); mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight); + if (targetHeight != currentHeight) { + mScaleAnimation.setFloatValues(targetHeight); + mScaleAnimation.setupStartValues(); + mScaleAnimation.start(); + } + mCallback.setUserLockedChild(mCurrView, false); + + mExpanding = false; + mExpansionStyle = NONE; + if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView); - clearView(); } private void clearView() { @@ -357,7 +555,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mCurrViewTopGlow = g.findViewById(R.id.top_glow); mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow); if (DEBUG) { - String debugLog = "Looking for glows: " + + String debugLog = "Looking for glows: " + (mCurrViewTopGlow != null ? "found top " : "didn't find top") + (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom"); Slog.v(TAG, debugLog); @@ -367,8 +565,20 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { @Override public void onClick(View v) { - initScale(v); - finishScale(true); + startExpanding(v, STRETCH); + finishExpanding(true); + clearView(); + } + /** + * Triggers haptic feedback. + */ + private synchronized void vibrate(long duration) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) + mContext.getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); } } + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 1204a89..8d7734e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -783,16 +783,20 @@ public abstract class BaseStatusBar extends SystemUI implements int N = mNotificationData.size(); for (int i = 0; i < N; i++) { NotificationData.Entry entry = mNotificationData.get(i); - if (i == (N-1)) { - if (DEBUG) Slog.d(TAG, "expanding top notification at " + i); - expandView(entry, true); - } else { - if (!entry.userExpanded()) { - if (DEBUG) Slog.d(TAG, "collapsing notification at " + i); - expandView(entry, false); + if (!entry.userLocked()) { + if (i == (N-1)) { + if (DEBUG) Slog.d(TAG, "expanding top notification at " + i); + expandView(entry, true); } else { - if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i); + if (!entry.userExpanded()) { + if (DEBUG) Slog.d(TAG, "collapsing notification at " + i); + expandView(entry, false); + } else { + if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i); + } } + } else { + if (DEBUG) Slog.d(TAG, "ignoring notification being held by user at " + i); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index dfd8cf8..c82f250 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -71,6 +71,18 @@ public class NotificationData { public boolean setUserExpanded(boolean userExpanded) { return NotificationData.setUserExpanded(row, userExpanded); } + /** + * Return whether the entry is being touched by the user. + */ + public boolean userLocked() { + return NotificationData.getUserLocked(row); + } + /** + * Set the flag indicating that this is being touched by the user. + */ + public boolean setUserLocked(boolean userLocked) { + return NotificationData.setUserLocked(row, userLocked); + } } private final ArrayList<Entry> mEntries = new ArrayList<Entry>(); private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() { @@ -197,4 +209,18 @@ public class NotificationData { public static boolean setUserExpanded(View row, boolean userExpanded) { return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded); } + + /** + * Return whether the entry is being touched by the user. + */ + public static boolean getUserLocked(View row) { + return readBooleanTag(row, R.id.user_lock_tag); + } + + /** + * Set whether the entry is being touched by the user. + */ + public static boolean setUserLocked(View row, boolean userLocked) { + return writeBooleanTag(row, R.id.user_lock_tag, userLocked); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 9317561..2628631 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -53,6 +53,7 @@ public class StatusBarWindowView extends FrameLayout int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight); mExpandHelper.setEventSource(this); + mExpandHelper.setScrollView(scroller); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java index 61e5ab6..89eed1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -78,6 +78,7 @@ public class NotificationRowLayout super(context, attrs, defStyle); mRealLayoutTransition = new LayoutTransition(); + mRealLayoutTransition.setAnimateParentHierarchy(true); setLayoutTransitionsEnabled(true); setOrientation(LinearLayout.VERTICAL); @@ -161,7 +162,12 @@ public class NotificationRowLayout return NotificationData.setUserExpanded(v, userExpanded); } + public boolean setUserLockedChild(View v, boolean userLocked) { + return NotificationData.setUserLocked(v, userLocked); + } + public void onChildDismissed(View v) { + if (DEBUG) Slog.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews); final View veto = v.findViewById(R.id.veto); if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) { veto.performClick(); @@ -225,6 +231,7 @@ public class NotificationRowLayout * get removed properly. */ public void setViewRemoval(boolean removeViews) { + if (DEBUG) Slog.v(TAG, "setViewRemoval: " + removeViews); mRemoveViews = removeViews; } |
