Les nouveautés et Tutoriels de Votre Codeur | SEO | Création de site web | Création de logiciel

seo Gmail for Mobile HTML5 Series: CSS Transforms and Floaty Bars 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of what we've learned in a brief series of follow-up blog posts. This week, I'll talk about different ways to animate the floaty bar.

Even from the earliest brainstorming days for our new version of Gmail for iPhone and Android-powered devices, we knew we wanted to try something novel with menu actions: a context-sensitive, always-accessible UI element that follows conveniently as a user scrolls. Thus, the "floaty bar" was born! It took us a surprisingly long time, experimenting with different techniques and interactions, to converge on the design you see today. Let's look under the covers to see how the animation is achieved. You may be surprised to find that the logic is actually quite simple!


Screenshots of the floaty bar in action

In CSS:
.CSS_FLOATY_BAR {
...
top: -50px; /* start off the screen, so it slides in nicely */
-webkit-transition: top 0.2s ease-out;
...
}
In JavaScript:
// Constructor for the floaty bar
gmail.FloatyBar = function() {
this.menuDiv = document.createElement('div');
this.menuDiv.className = CSS_FLOATY_BAR;
...
};

// Called when it's time for the floaty bar to move
gmail.FloatyBar.prototype.setTop = function() {
this.menuDiv.style.top = window.scrollY + 'px';
};

// Called when the floaty bar menu is dismissed
gmail.FloatyBar.prototype.hideOffScreen = function() {
this.menuDiv.style.top = '-50px';
};

gmail.floatyBar = new gmail.FloatyBar();

// Listen for scroll events on the top level window
window.onscroll = function() {
...
gmail.floatyBar.setTop();
...
};
The essence here is that when the viewport scrolls, the floaty bar 'top' is set to the new viewport offset. The -webkit-transition rule specifies the animation parameters. (The 'top' property is to be animated, over 0.2s, using the ease-out timing function.) This is the animation behavior we had at launch, and it works just fine on Android and mobile Safari browsers.

However, there's actually a better way to achieve the same effect, and the improvement is particularly evident on mobile Safari. The trick is to use "CSS transforms". CSS transforms is a mechanism for applying different types of affine transformations to page elements, specified via CSS. We're going to use a simple one which is translateY. Here's the same logic, updated to use CSS transforms.

In CSS:
.CSS_FLOATY_BAR {
...
top: -50px; /* start off the screen, so it slides in nicely */
-webkit-transition: -webkit-transform 0.2s ease-out;
...
}
In JavaScript:
// Called when it's time for the floaty bar to move
gmail.FloatyBar.prototype.setTop = function() {
var translate = window.scrollY - (-50);
this.menuDiv.style['-webkit-transform'] = 'translateY(' + translate + 'px)';
};

// Called when the floaty bar menu is dismissed
gmail.FloatyBar.prototype.hideOffScreen = function() {
this.menuDiv.style['-webkit-transform'] = 'translateY(0px)';
};
Upon every scroll event, the floaty bar is translated vertically to the new viewport offset (modulo the offscreen offset which is important to the floaty bar's initial appearance). And, why exactly is this such an improvement? Even though the logic is equivalent, iPhone OS's implementation of CSS transforms is "performance enhanced", whilst our first iteration (animating the 'top' property) is performed by the OS in software. That's why the experience was unfortunately somewhat chunky at times, depending on the speed of the iPhone hardware.

You'll see smoother looking floaty bars coming very soon to an iPhone near you. This is just the first in a series of improvements we're planning for the mobile Gmail floaty bar. Watch for them in our iterative webapp, rolling out over the next couple of weeks and months!



Previous posts from Gmail for Mobile HTML5 Series:
HTML5 and Webkit pave the way for mobile web applications
Using AppCache to launch offline - Part 1
Using AppCache to launch offline - Part 2
Using AppCache to launch offline - Part 3
A Common API for Web Storage
Suggestions for better performance
Cache pattern for offline HTML5 web application
Using timers effectively
Autogrowing Textareas
Reducing Startup Latency
2013, By: Seo Master

seo CSS3 Transitions and Transforms in Gmail for the iPad 2013

Seo Master present to you: The Mobile Gmail team recently announced a new stacked cards interface for the iPad. In this interface we make use of CSS3 transitions and transforms to provide a more intuitive interface that has a look and feel that is similar to native applications. In this post we will describe CSS3 transitions and transforms and how they were used to develop this interface. All of the CSS and JavaScript examples currently work only in WebKit-based browsers, such as Safari on the iPad. However, Mozilla-based browsers have their own versions of WebKit-based extensions that use the ‘-moz’ prefix, and that should behave similarly.

CSS3 Transitions

CSS3 transitions allow the browser to animate the change of a CSS property from an initial value to a final value. A transition is configured by setting four CSS properties on an HTML element:
  • -webkit-transition-property
  • -webkit-transition-duration
  • -webkit-transition-timing-function
  • -webkit-transition-delay
The -webkit-transition-property property identifies the CSS properties where changes to the property will trigger a transition between the old value of the property and the new value. The -webkit-transition-duration property specifies, in milliseconds, the length of time over which the transition should take place. The -webkit-transition-timing-function property describes the speed at which the transition progresses over the duration of the transition. For example, -webkit-transition-timing-function: ease-in-out describes a transition that will proceed slowly at the beginning and the end of the transition, but that will proceed quickly during the middle of the transition. You can also provide a custom, cubic-bezier function for a higher degree of control over the timing. The -webkit-transition-delay property specifies a delay, measured in milliseconds, before the transition begins.

The transition properties can also be set simultaneously using the -webkit-transition property, by simply specifying them in the above order. Once the transitions properties are set and up to the point where the value of -webkit-transition-property is changed, all modifications of the specified CSS properties will trigger transitions.

CSS3 Transforms

CSS3 transforms allow the rendering of an HTML element to be modified using 2D and 3D transformations such as rotation, scaling, and translations. Transforms are applied by setting the -webkit-transform CSS property with the desired list of transforms. Each transform takes the form of a transformation function, such as translate3d or rotate, and a list of parameters enclosed in brackets. For example, to move an object to the right by 100 pixels and rotate it by 45 degrees you can use the -webkit-transform property:

-webkit-transform: translate(100px, 0) rotate(45deg);

Using -webkit-transform as the transition property when moving an element is advantageous relative to using the standard top and left properties because transitions using -webkit-transform are hardware-accelerated in Safari. An exception here is that it seems that 2D translations are not hardware-accelerated. But, since any 2D translation is equivalent to a corresponding 3D translation with the same translations in the x and y and no translation in the z axis, it is easy to use a hardware accelerated translate3d(x, y, 0) transform instead of a non-hardware accelerated translate(x, y) transform.

Terminology

There are a few terms here that begin with ‘trans,’ and they can easily be confused if you are not familiar with them. Here they are again:
  • Transition: An implicit animation of CSS properties between an initial and a final value.
  • Transform: A modification to the appearance of an HTML element by manipulating it in a 2D or 3D space.
  • Translation: A particular type of transformation that moves the HTML element in 2D or 3D space.
Stacked Cards Interface

In the stacked cards interface, cards representing selected conversations transition onto the screen when their corresponding conversation is selected, and transition off of the screen when it is deselected.

When cards are selected, they are transitioned out from underneath the conversation list on the left side of the application into the selected conversation area on the right side of the application. To move the card onto the screen, we set an initial transform, configure the transition, and finally apply the desired final transform to the element.

To simplify the layout, the un-transformed position of each card is its normal position in the selected conversation area. This allows the card to have no translation applied when in this position, although it will need a translation to animate the movement. Initially the card has a transform that translates it to the left. The z-index property is used to ensure that the card will render underneath the conversation list. The rotation of the card is also initially applied, since we chose not to have the card rotate as it transitions onto the screen.

card.style.WebkitTransform =
‘translate3d(-700px, 0, 0) rotate(5deg)’;

Since the particular translation and rotation can vary, we chose to apply this property using JavaScript rather than including it in the CSS class applied to the card. It is important that the CSS3 transition is not yet applied because we do not want this transform to be a transition. Moreover, it is important that the card is rendered at its initial transform before the transition is configured and the destination transform is applied. This is easily achieved by wrapping these next steps in a call to window.setTimeout with a timeout of 0 ms.

window.setTimeout(function() {
card.style.WebkitTransition =
‘-webkit-transform 300ms ease-in-out’;
card.style.WebkitTransform =
‘translate3d(0, 0, 0) rotate(5deg)’;
}, 0);

Completion of the Transition

It is useful to know when the transition is complete. In the stacked cards interface, we use this to improve performance by setting display:none on obscured cards so that they do not need to be rendered. Adding an event listener allows the application to be notified when the transition has completed.

element.addEventListener(‘webkitTransitionEnd’, listener, false);

Interrupting a Transition

In some cases, you may want to change a transition while it is in progress. For example, if the user unselected a conversation while the corresponding card was still animating onto the screen, we might apply a new transition to send the card back off of the screen again. When you apply a new CSS value while a transition is already in progress, a new transition will occur between the current value of the property in the transition and the new value that you apply. For example, suppose a card is halfway through it’s transition onto the screen, and we apply this CSS transform:

card.style.WebkitTransform = 
‘translate3d(-700px, 0, 0) rotate(5deg)’;

Since the transition properties are still configured, a new transition will occur. The initial value for the transition will be the halfway point - approximately translated3d(-350px, 0, 0) rotate(5deg). The final value will be translate3d(-700px, 0, 0) rotate(5deg). The full duration of the transition will still apply, so the card will move about half as quickly as it usually does. It is possible to determine the current transform applied to an HTML element using the WebKitCSSMatrix and to use this to recalculate more appropriate transition parameters, but this is outside the scope of this post.

Conclusion
I hope that this introduction to CSS3 transitions and transforms has been useful, and that the insight into the implementation of Mobile Gmail on the iPad has been interesting. Based on positive feedback, the Mobile Gmail team is looking forward to making more use of transitions and transforms in the future.

2013, By: Seo Master

seo Gmail for Mobile HTML5 Series: Autogrowing Textareas 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of what we've learned in a brief series of follow-up blog posts. This week I'll talk about autogrowing textareas for entering large amounts of text.

When composing a long message in a web app, regardless of whether it's on a desktop or a mobile device, you really want to see as much of your draft as possible and make use of all the available screen space.
One of my biggest gripes are fixed-size textareas that restrict me to only a couple lines of visible text when my screen is actually many times larger than the size of the textarea.

In today's blog post, I'll share a JavaScript solution for textareas that automatically grow (vertically) to the size of the content. They make composing long messages much easier and, for all those iPhone users out there, takes away the need to scroll with the dreaded magnifying glass! We're working on getting this into Gmail for mobile but here it is now as a teaser of things to come.





Measuring the height of the content

The first step is to detect when the content has changed. Some solutions on the net recommend using a timer (see our previous post to find out more about timers) to check if content has changed. However, that approach is not ideal on a mobile device, where both battery life and processor power are limited.

Instead, we will listen for key-up events from the browser. This guarantees that we only measure the textarea when the content has actually changed.

<textarea id="growingTextarea" onkeyup="grow();"></textarea>

The second step is to actually measure the height of the content. There are solutions on the net that recommend keeping a copy of the content in a div and measuring the div to get the height; however, due to memory and processor limitations on a mobile device, those solutions don't scale well when the content gets large (and it's also hard to replicate textarea line wrapping behavior exactly in a div).

Therefore we will make use of the scrollHeight and clientHeight properties. For our purposes, scrollHeight is the height of all the content while clientHeight is the height of the content that's visible in the textarea (for more precise definitions, see scrollHeight and clientHeight)
function grow() {
var textarea = document.getElementById('growingTextarea');
var newHeight = textarea.scrollHeight;
var currentHeight = textarea.clientHeight;

}
One limitation of using scrollHeight and clientHeight is that we aren't able to shrink the textarea when content is deleted. When all the content of a textarea is visible, the scrollHeight is equal to the clientHeight. Therefore we aren't able to detect that our textarea is actually larger than the minimum size required to fit all the content (please do leave a comment if you think of a solution that doesn't require re-rendering the page).

Growing the textarea

To grow the text area, we modify the height CSS property:
if (newHeight > currentHeight) {
textarea.style.height = newHeight + 5 * TEXTAREA_LINE_HEIGHT + 'px';
}
Notice how we only change the height if newHeight > currentHeight. Depending on the browser, changing the height (even if it's to the same value) will cause the page to re-render. On a mobile device, we want to try our best to minimize the number of operations.

Also, we grow the textarea by five lines every time we grow. From a UI perspective, this reduces the amount of jitter when composing a message but, from a performance perspective, this reduces the number of times we need to re-render the page.

(Quick note for developers implementing this for a browser with scrollbars: you might want to modify the CSS overflow property to preventing the scrollbar from appearing and disappearing as you grow your textarea)

The complete solution

Growing textareas are easy to implement and they make composing long messages infinitely more usable. So go out there add it to all your web apps!
<script>
// Value of the line-height CSS property for the textarea.
var TEXTAREA_LINE_HEIGHT = 13;

function grow() {
var textarea = document.getElementById('growingTextarea');
var newHeight = textarea.scrollHeight;
var currentHeight = textarea.clientHeight;

if (newHeight > currentHeight) {
textarea.style.height = newHeight + 5 * TEXTAREA_LINE_HEIGHT + 'px';
}
}
</script>
<textarea id="growingTextarea"
onkeyup="grow();">
</textarea>

Previous posts from Gmail for Mobile HTML5 Series
Using timers effectively

2013, By: Seo Master

seo Gmail for Mobile HTML5 Series: Suggestions for Better Performance 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of our learnings in a brief series of follow-up blog posts. This week, I'll talk about a few small things you can do to improve performance of your HTML5-based applications. Our focus here will be on performance bottlenecks related to the database and AppCache.

Optimizing Database Performance

There are hundreds of books written about optimizing SQL and database performance, so I won't bother to get into these details, but instead focus on things which are of particular interest for mobile HTML5 apps.

Problem: Creating and deleting tables is slow! It can take upwards of 200 ms to create or delete a table. This means a simple database schema with 10 tables can easily take 2-4 seconds (or more!) just to delete and recreate the tables. Since this often needs to be done at startup time, this really hurts your launch time.

Solution: Smart versioning and backwards compatible schema changes (whenever possible). A simple way of doing this is to have a VERSION table with a single row that includes the version number (e.g., 1.0). For backwards-compatible version changes, just update the number after the decimal (e.g., 1.1) and apply any updates to the schema. For changes that aren't backwards compatible, update the number before the decimal (e.g., 2.0) at which point you can drop all the tables and recreate them all. With a reasonable schema design to begin with, it should be very rare that a schema change is not backwards compatible and even if this happens every month or so, users should get to use your application 20, 30 even 100 times before they hit this startup delay again. If your schema changes very infrequently, a simple 1, 2, 3 versioning scheme will probably work fine; just make sure to only recreate the database when the version changes!

Problem: Queries are slow! Queries are faster than creates and updates, but they can still take 100ms-150ms to execute. It's not uncommon for traditional applications to execute dozens or even hundreds of queries at startup – on mobile this is not an option.

Solution: Defer and/or combine queries. Any queries that can be deferred from startup (or at any other significant point in the application) should be deferred until the data is absolutely needed. Adding 2-3 more queries on a user-driven operation can turn an action from appearing instantaneous to feeling unresponsive. Any queries that are performed at startup should be optimized to require as few hits to the database as possible. For example, if you're storing data about books and magazines, you could use the following two queries to get all the authors along with the number of books and magazine articles they've writen:

SELECT Author, COUNT(*) as NumArticles
FROM Magazines
GROUP BY Author
ORDER BY NumArticles;

SELECT Author, COUNT(*) as NumBooks
FROM Books
GROUP BY Author
ORDER BY NumBooks;


This will work fine, but the additional query will generally cost you about 100-200 ms over a different (albeit less pretty) query like:

SELECT Author, NumPublications, PubType
FROM (
SELECT Author, COUNT(*) as NumPublications, 'Magazine' as PubType, 0 as SortIndex
FROM Magazines
GROUP BY Author
UNION
SELECT Author, COUNT(*) as NumPublications, 'Book' as PubType, 1 as SortIndex
FROM Books
GROUP BY Author
)
ORDER BY SortIndex, NumPublications;

This will return all the entries we want, with the magazine entries first in increasing order of number of articles, followed by the book entries, in increasing order of the number of books. This is a toy example and there are clearly other ways of improving this, such as merging the Magazines and Books tables, but this type of scenario shows up all the time. There's always a trade-off between simplicity and speed when dealing with databases, but in the case of HTML5 on mobile, this trade-off is even more important.

Problem: Multiple updates is slow!

Solution: Use Triggers whenever possible. When the result of a database update requires updating other rows in the database, try to do it via SQL triggers. For example, let's say you have a table called Books listing all the books you own and another called Authors storing the names of all the authors of books you own. If you give a book away, you'll want to remove it from the Books table. However, if this was the only book you owned by that author, you would also want to remove the author from the Authors table. This can be done with two UPDATE statements, but a "better" way is to write a trigger that automatically deletes the author from the Authors table when the last book by this author is removed. This will execute faster and because triggers happen asynchronously in the background, it will have less of an impact on the UI than executing two statements. Here's an example of a simple trigger for this case:

CREATE TRIGGER IF NOT EXISTS RemoveAuthor
AFTER DELETE ON Books
BEGIN
DELETE FROM Authors
WHERE Author NOT IN
(SELECT Author
FROM Books);
END;
We'll get into more detail on triggers and how to use them in another performance post to come.

Optimizing AppCache Performance

Problem: Logging in is slow!

Solution: Avoid redirects to the login page. App-Cache is great because it can launch the application without needing to hit the network, which makes it much faster and allows you to launch offline. One problem you might encounter though, is that the application will launch and then you'll need to hit the network to get some data for the current user. At this point you'll have to check that the user is authenticated and it might turn out that they're not (e.g., their cookies might have expired or have been deleted). One option is to redirect the user to a login page somewhere, allow him to authenticate and then redirect him back to the application. Regardless of whether or not the login page is listed in the manifest, when it redirects back to your application, the entire application will reload. A nicer approach is for the application itself to display an authentication interface which sends the credentials and does the authentication seamlessly in the background. This will avoid any additional reloads of the application and makes everything feel faster and better integrated.

Problem: AppCache reloading causes my app to be slow!

Solution: List as few URLs in the manifest as possible. In a series of posts on code.google.com, we talked about the HTML5 AppCache manifest file. An important aspect of the manifest file is that when the version gets updated, all the URLs listed in the file are fetched again. This happens in the background while the user is using the application, but opening all these network connections and transferring all that data can cause the application to slow down considerably during this process. Try to setup your application so that all the resources can be fetched from as few URLs as possible to speed up the manifest download and minimize this effect. Of course you could also just never update your manifest version, but what's the point of having rapid development if you never make any changes?


That's a brief intro to some performance considerations when developing HTML5 applications. These are all issues that we ran into ourselves and have either fixed or are in the process of fixing in our application. I hope this helps you to avoid some of the issues we ran into and makes your application blazing fast!

We plan to write several more performance related posts in the future, but for now stay tuned for next post where we'll discuss the cache pattern for building offline capable web applications.



Previous posts from Gmail for Mobile HTML5 Series
HTML5 and Webkit pave the way for mobile web applications
Using AppCache to launch offline - Part 1
Using AppCache to launch offline - Part 2
Using AppCache to launch offline - Part 3
A Common API for Web Storage
2013, By: Seo Master

seo Gmail for Mobile HTML5 Series: A Common API for Web Storage 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of our learnings in a brief series of follow up blog posts. Over the last few weeks we've talked about how to use the AppCache functionality of HTML5 to launch an application offline. We discussed the impact that AppCache can have on your mobile web applications, as you enable users to launch your app faster in the face of flaky or slow internet connections. This week, I'll talk about how we're using both HTML5 Structured Storage and the Google Gears Database to make devices tolerate flaky network connections.



Although these technologies allow web applications to cache user data on the mobile device and perform data modifications locally, HTML5 Structured Storage uses an asynchronous model, where the Google Gears Database uses a synchronous model. This difference makes it difficult to develop an application on top of both platforms. We dealt with this problem by creating the Web Storage Portability Layer (WSPL) for Gmail. Coming soon under a liberal open source license to code.google.com/p/webstorageportabilitylayer, WSPL provides a common API that supports an identical asynchronous programming model for both platforms by using a worker thread in Gears. Let's take a look!

The WSPL consists of a collection of classes that provide asynchronous transactional access to both Gears and HTML5 databases. It can be used to execute nested statements within callbacks, create statement templates, and optionally control the synchronous/asynchronous modes of the Gears Database Wrapper. There are five basic classes.

google.wspl.Statement - A parametrizable SQL statement class
google.wspl.Transaction - Used to execute one or more Statements with ACID properties
google.wspl.ResultSet - Arrays of JavaScript hash objects, where the hash key is the table column name
google.wspl.Database - A connection to the backing database, also provides transaction support
google.wspl.DatabaseFactory - Creates the appropriate HTML5 or Gears database implementation

Let's take a look at how we can use this API to perform a simple query, starting with the creation of a Database. Note that you'll need to provide a URL to the worker file hosted from your domain.

var database = google.wspl.DatabaseFactory.createDatabase('db name', 'http://yourdomain/dbworker.js');

You can then execute SQL statements without worrying about the specifics of HTML5 and Gears. Refer to the recent blog posts about AppCache to find steps you can follow to see your database contents using sqlite3.
var statement = google.wspl.Statement('SELECT col from test_table;');
database.createTransaction(function(tx) {
tx.executeAll([statement], {onSuccess: function(tx, resultSet) {
// Statement succeeded.

for(; resultSet.isValidRow(); resultSet.next()) {
window.console.info(resultSet.getRow()['col']);
}
}, onFailure: function(error) {
// Statement failed.
}});
}, {onSuccess: function() {
// After transaction commits, before any other starts.
}, onFailure: function(error) {
// After transaction fails, before any other starts.
}});
I've found that using the Gears database asynchronously will nicely split up the JavaScript execution, allowing event handlers and other code to execute between the callbacks. This can improve the responsiveness of your application if you're using long transactions. You can also use SQL triggers to avoid the read-modify-write pattern that causes "ping ponging" between threads -- either the main thread and Gears worker or the main thread and the HTML5 SQL thread.

That's all I'll show you for now, but you can look for more details about the Web Storage Portability Layer at Google I/O, May 27-28 in San Francisco where we'll be presenting a session on the architecture of a generic application using HTML5. We'll also be available at the Developer Sandbox and are looking forward to meeting you in person. Stay tuned for the next post where we'll talk about improving the performance of HTML5-based web applications.

2013, By: Seo Master

seo Gmail for mobile HTML5 Series - Part 3: Using AppCache to Launch Offline 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices built on HTML5. We shared the behind-the-scenes story through this blog and decided to share more of our learnings in a brief series of follow up blog posts. In the last two posts, we covered everything you need to know in order to make effective use of AppCache. This week, we'll be having some fun and trying to disect the inner workings of AppCache by looking at the database it uses to store its resources. Before we start though, I'd like to point out one tip that can be useful while debugging AppCache related problems on the iPhone: how to clear your Application Cache.

There are two steps involved here:
  1. Go to Settings->Safari and tap "Clear Cache".
  2. Open Safari and terminate it by holding down the home screen button for 10 seconds.
The first step is pretty intuative. The problem is that the browser does not immediately notice that the cache has been cleared, and so needs to be restarted.

Now onto the fun stuff! There is no way to inspect the application cache from within the browser. However, if you are using the iPhone Simulator to develop your webapp, you can find all of the Application Cache resources and metadata in a SQLite3 database located at:

~/Library/Application Support/iPhone Simulator/User/Library/Caches/com.apple.WebAppCache/ApplicationCache.db

Let's have a look at what is contained within this database.

$ sqlite3 ApplicationCache.db
SQLite version 3.4.0
Enter ".help" for instructions
sqlite> .mode column
sqlite> .headers on
sqlite> .tables
CacheEntries CacheResourceData CacheWhitelistURLs FallbackURLs
CacheGroups CacheResources Caches SchemaVersion
sqlite> select * from CacheGroups;
id manifestHostHash manifestURL newestCache
---------- ---------------- ------------------------------------------------- -----------
1 906983082 http://mail.google.com/mail/s/?v=ma&name=sm 1

The CacheGroups table holds an overview of what manifests exist. A manifest is identified by its URL and the manifestHostHash is used to track when the contents of a manifest changes.

sqlite> select * from Caches;
id cacheGroup
---------- ----------
1 1

Here you can see that I have only one cache in my database. If the Application Cache was in the middle of updating the cache, there would be a second entry listed here for the cache currently being downloaded.

sqlite> select * from CacheEntries limit 1;
cache type resource
---------- ---------- ----------
1 2 1

The CacheEntries table holds a one-to-many relationship between a cache and resources within it.

sqlite> select * from CacheResources where id=1;
id url statusCode responseURL
---------- ------------------------------------------- ---------- -----------------------
1 http://mail.google.com/mail/s/?v=ma&name=sm 200 http://mail.google.c...

mimeType textEncodingName headers data
------------------- ---------------- --------------
text/cache-manifest utf-8

sqlite> .schema CacheResourceData
CREATE TABLE CacheResourceData (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB);

This shows what information is stored for each resources listed in a manifest. As you can see the CacheResources and CacheResourceData tables contain everything that is needed in order to simulate a network response to a request for a resource. Let's see exactly what is stored in the database for Mobile Gmail's database.

sqlite> select type,url,mimeType,statusCode from CacheEntries,CacheResources where resource=id;
type url mimeType statusCode
---------- ---------------------------------------------- ------------------- ----------
2 http://mail.google.com/mail/s/?v=ma&name=sm text/cache-manifest 200
4 http://mail.google.com/mail/images/xls.gif image/gif 200
4 http://mail.google.com/mail/images/pdf.gif image/gif 200
4 http://mail.google.com/mail/images/ppt.gif image/gif 200
4 http://mail.google.com/mail/images/sound.gif image/gif 200
4 http://mail.google.com/mail/images/doc.gif image/gif 200
4 http://mail.google.com/mail/images/graphic.gif image/gif 200
1 http://mail.google.com/mail/s text/html 200
4 http://mail.google.com/mail/images/generic.gif image/gif 200
4 http://mail.google.com/mail/images/zip.gif image/gif 200
4 http://mail.google.com/mail/images/html2.gif image/gif 200
4 http://mail.google.com/mail/images/txt.gif image/gif 200

From this list, it is fairly easy to see what the meaning of the type field is. A host page has type 1, a manifest has type 2, and a normal resource has type 4. In order to know whether or not to load a page using AppCache, the browser checks this list to see if there is a URL of type 1 within it.

This concudes our three-part series on HTML5's Application Cache. Stay tuned for the next post where we will explore other areas of how we use HTML5 in Gmail. And just another reminder that we'll be at Google I/O, May 27-28 in San Francisco presenting a session on how we use HTML5. We'll also be available at the Developer Sandbox, looking forward to meeting you in person.

References
The HTML5 working draft: http://dev.w3.org/html5/spec/Overview.html

Apple's MobileSafari documentation: http://developer.apple.com/webapps/docs/documentation/AppleApplications/Reference/SafariJSRef/DOMApplicationCache/DOMApplicationCache.html

Webkit Source Code: http://trac.webkit.org/browser/trunk/WebCore/loader/appcache

2013, By: Seo Master

seo Gmail for mobile HTML5 Series - Part 2: Using AppCache to Launch Offline 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices built on HTML5. We shared the behind-the-scenes story through this blog and decided to share more of our learnings in a brief series of follow up blog posts. Last week we explained how to go about creating a simple manifest file, and how the browser uses it to load a page. This week we will go a bit more in-depth about the subject.

One of the problems we faced in creating our manifest file, was how to update it when our javascript changes. At first we thought that we might have to change one of the URLs each time we wanted to push an update. As it turns out, the URLs listed in the manifest do not have to change at all in order cause an update, changing the whitespace or a comment will also do the trick. For Gmail, we a comment in the manifest that contains a hash of all of the resources listed in the manifest. That way, if any of the resources change, the manifest will also change and cause a background update to occur for all of our clients. An example of what this looks like is shown below.

CACHE MANIFEST
# version: 3f1b9s84
jsfile1.js
... other URLs ...

There are other types of entries that are possible in a manifest, but that the iPhone does not currently support. According to the spec, there are 3 categories of URLs that can be listed in a manifest:
  • Cache (what we have dealt with so far),
  • Fallback,
  • Network
Although fallback and network URLs are not yet supported on the iPhone, they are mostly supported in the Webkit Nightly builds. Network URLs are those that are never cached by AppCache, and that are allowed to be satisfied by the network. Fallback URLs are those that are attempted, and then satisfied by by AppCache only if the network attempt fails. Both Network and Fallback URLs are prefix matches. An example of what this looks like is shown below.

CACHE MANIFEST
jsfile1.js

NETWORK:
/images/

FALLBACK:
/thumbnails/ images/missing_thumb.jpg

This manifest tells the browser that GET requests to any URL under /images/ are allowed to hit the server. Without this being listed, GET requests for it would fail immediately. This manifest also tells the browser that URLs under /thumbnails/ are allowed to hit the server, but if they fail, satisfy the request by server missing_thumb.jpg, which will be stored in AppCache.

So far all of the features we've covered about AppCache have not needed any Javascript to use them. This is undoubtedly by design, as it makes it extremely easy to use. However, it is always useful to know what advanced functionality can be unlocked using Javascript. The Application Cache is exposed as a singleton through window.applicationCache. It provides events that can be used to indicate when updates are happening and a status property that can be one of:
  • 0 - UNCACHED
  • 1 - IDLE
  • 2 - CHECKING
  • 3 - DOWNLOADING
  • 4 - UPDATEREADY
In Gmail, we use the status property to determine if the page was loaded out of AppCache, or if it was loaded from the network. In order to do this, we have the following code run at the very start of page load:

if (window.applicationCache.status == 0) {
// Page was loaded from the Network.
} else {
// Page was loaded from AppCache
}

There are also a couple of functions available, swapCache and updateCache, which we'll not go into detail on since we have not found any use for them yet.

Stay tuned for the next post where we will explore how to use the sqlite3 command-line tool to inspect the iPhone Simulator's AppCache database. And just another reminder that we'll be at Google I/O, May 27-28 in San Francisco presenting a session on how we use HTML5. We'll also be available at the Developer Sandbox, looking forward to meeting you in person.

References

The HTML5 working draft:
http://dev.w3.org/html5/spec/Overview.html

WHATWG working draft:
http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html#appcache

Apple's MobileSafari documentation:
http://developer.apple.com/webapps/docs/documentation/AppleApplications/Reference/SafariJSRef/DOMApplicationCache/DOMApplicationCache.html

Webkit Source Code:
http://trac.webkit.org/browser/trunk/WebCore/loader/appcache


2013, By: Seo Master

seo Gmail for mobile HTML5 Series: Using AppCache to Launch Offline - Part 1 2013

Seo Master present to you: On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices built on HTML5. We shared the behind-the-scenes story through this blog and would like to share more of our learnings in a brief series of follow up blog posts.

The HTML5 draft adds a lot of exciting functionality to browsers. Perhaps the most exciting is adding a way for websites to be launched offline. For devices that have a high bandwidth and highly available connection, offline functionality might not be so important. For web applications running on mobile devices however, being able to launch offline can dramatically improve the web application experience.
AppCache support on the iPhone is still under development, but as of firmware 2.2.1, it is usable.

To make use of AppCache, a webpage must provide a "manifest" to the browser that lists all of the URLs that it intends to use. Creating an HTML5 manifest file is extremely simple, as shown by the following example.
CACHE MANIFEST
jsfile1.js
jsfile2.js
styles.css
/images/image1.png
/images/image2.png
It is important to note that it is not necessary to list the URL of the main webpage in the manifest because it is treated as an implicit entry. However, if you have more than one top level URL that you want to be available offline, they must all be listed in the manifest. In addition, they must all set a manifest attribute on the HTML tag that points to the manifest. For example, if the manifest URL was "/sitemanifest", then each page in the site would have an HTML tag that looked like this:
<html manifest="/sitemanifest">
Finally, the manifest must be served using the content type "text/cache-manifest". And that's it!

So now that you know how to create a manifest for your site, it's a good idea to know what's going on during page load. When the page is loaded for the first time, it will load as if there is no application cache associated with it. Once it has finished loading, the browser will fetch the manifest and all resources listed in it that have not already been fetched during page load. From this point on, any GET request that your page makes that is not listed in the manifest will fail, and any GET request that is listed in it will not hit the network, but will be satisfied by the cache. Once your page is loaded into AppCache, the next time the user loads the site, all of the resources will be served out of the cache. The only GET request done on page load will be for the manifest file, in order to see if it has changed. If it has changed, then all of the resources in it are fetched in the background and will be used the next time the user refreshes the page.

Stay tuned for the next post where we will share more about what we know about AppCache and how we use it on the Gmail team. Also, we'll be at Google I/O, May 27-28 in San Francisco presenting a session on how we use HTML5. We'll also be available at the Developer Sandbox, and we look forward to meeting you in person.

References

The HTML5 working draft:
http://dev.w3.org/html5/spec/Overview.html

Apple's MobileSafari documentation: http://developer.apple.com/webapps/docs/documentation/AppleApplications/Reference/SafariJSRef/DOMApplicationCache/DOMApplicationCache.html

Webkit Source Code:
http://trac.webkit.org/browser/trunk/WebCore/loader/appcache

2013, By: Seo Master

seo HTML5 and WebKit pave the way for mobile web applications 2013

Seo Master present to you: When I first started at Google, we were building a Java ME email client for the phones of the day. It's an excellent product - still the fastest, slickest way to get your Gmail on many devices because of Java ME's widespread penetration. Yet it always bothered us that this client didn't really leverage the core strength of the desktop Gmail platform: sheer ease of access from anywhere, and constant updates and improvements. To use the client, you have to figure out how to install it and possibly navigate confusing network permission pop-up dialogs, and improvements could only be rolled out a few times a year in upgrades that required every user to download and reinstall their software.

The mobile team started thinking about how we could bring the benefits of the server-side approach to these clients. We started thinking about a world where we could deliver a GUI specified in XML to a Java ME client, enabling us to iterate on the server side and deliver new features that could delight users when they were ready, rather than on a lengthy release cycle. I was especially struck by a friend who said "What I like about Gmail is that it just constantly keeps getting better. It's like waking up to a new little present from Google each month!" We wanted our mobile users to feel the same way, so we felt the logical thing to do would be to build a general client that could be controlled by the server.

Not too long after, the team first saw the new Android browser. Still in its early stages, the Android browser was built on the latest version of WebKit and could render desktop pages with ease. The XHTML, images, JavaScript, and CSS that could be rendered on this platform presented great potential for building very high-end web applications. However, this was ages before Android was due to ship and Android would only be one of many mobile platforms.

Those drawbacks aside, we couldn't help but think that new browsers in Android's league would eventually become a reality. These powerful browsers could have the kind of functionality we needed to build top-notch, offline user interfaces that didn't need to be "installed" by users or "upgraded". Gmail could be Gmail: a constantly evolving way to handle lots of email quickly and efficiently. The only fly in the ointment was the need for Gears: users would have to download a browser plug-in, and most web browsers on mobile devices don't even support that. What we really needed was for Gears to inspire innovation in HTML itself, so that the whole web could move forward.

Enter HTML5. We're very excited about the evolving HTML5 standard because it enables mobile and desktop website designers to deliver the advantages of client-side and server side development to their users simultaneously! New APIs let web applications start offline and store data on the client. The canvas API lets you draw complex user interfaces, or you can use advanced CSS tricks to get the browser to render a rich UI. In addition, the W3C Geolocation API is being adopted and implemented by browser developers, enabling entire new categories of web applications to be built. The benefits are clear: you can develop fantastic new applications, benefit from server-side analytics and iteration to deliver features that your users want, and know that offline functionality keeps things running as the user moves in and out of coverage. Your users can enjoy fast, capable web apps that they can access from any device, without the need to copy their data from place to place or worry about installing software or being online.

We decided to build new versions of mobile Gmail and mobile Calendar on top of this functionality. First, we built a small javascript wrapper around the database functionality in HTML5 and Gears. This wrapper abstracts away the differences between the two APIs, so that our applications are supported on the broadest set of browsers possible while older browsers get updated with implementations of the new offline APIs. We noticed that we weren't the only ones thinking about this: a quick search shows that other developers saw the similarities too. The main difference between the Gears database API and the HTML5 database API is that the Gears API is synchronous, requiring separate worker threads to do the database calls, while the HTML5 database API uses callbacks and is asynchronous. With the wrapper built, we knew our code would run on all high-end mobile browsers today, and look forward to even more distribution as everybody implements HTML5.

We knew we could apply various approaches to building better experiences for Gmail and Calendar. The key principle we kept in mind is an age-old one: KISS. Simply caching responses in the database for re-use is surprisingly effective: you can get a lot of improvement with just a read-only environment. This approach worked well for Calendar, where usage is predominantly read-only and we can rely on the user being online to make edits.

For Gmail, more complexity was needed. A queue of user actions needs to be maintained in the database (in case the user runs out of battery or powers down for their flight). Later, when the device is back online, it can execute that queue of mails to send, archive or delete, and so on.

Having the ability to store your data and actions offline isn't much good if you can't start the application while offline. So besides making use of the database API, we needed a way to get the application itself loaded without an internet connection. The HTML5 specification comes to the rescue here, with an application cache that is capable of storing all resources in your web app so that the browser can load them while offline. This API has just one small drawback: once you've decided you're going to override how HTTP GET works to fetch resources from the application cache, you also commit to never issuing a GET for a resource the cache doesn't know about. The specification contains methods for extending what URIs the cache knows exist, but these entry points are not widely implemented in production browsers. Instead, it's important to use HTTP POST requests for all dynamic data, since POST requests are never cached and therefore do reach the network.

The end result is an incredible thing: a web app that loads offline, and lets you read your Gmail or view your events provided the data have previously been cached. The experience is seamless as you ride the subway or the bus through terrible coverage: your data are ready, quickly, all the time. To see the new Gmail for mobile web app, go to gmail.com from an Android-powered device or iPhone (OS 2.2.1 or above).

Of course we didn't get there without a few hard knocks. As an evolving standard, HTML5 has been fast-changing target and we've skinned our knees and bruised ourselves along the way. So rather than just deliver the fruit of all those bumps and scratches to end users in our own products, we decided we wanted to write a few blog posts to share what we've learned so that others can take advantage of HTML5 as well. In addition, we look forward to opportunities like our upcoming developer conference, Google I/O (May 27-28 in San Francisco, CA) where we'll be hosting a few sessions, to meet you in person and share demos and know-how.

Whether or not you can make it out to Google I/O, stay tuned to the blog for upcoming posts with examples such as how to avoid making your databases too large, handle upgrades gracefully, and tune performance.

2013, By: Seo Master

seo OAuth access to IMAP/SMTP in Gmail 2013

Seo Master present to you: Google has long believed that users should be able to export their data and use it with whichever service they choose. For years, the Gmail service has supported standard API protocols like POP and IMAP at no extra cost to our users. These efforts are consistent with our broader data liberation efforts.

In addition to making it easier for users to export their data, we also enable them to authorize third party (non-Google developed) applications and websites to access their data at Google. One of the more common examples is allowing a social network to access your address book in order to send invitations to your friends.

While it is possible for a user to authorize this access by disclosing their Google Account password to the third party app, it is more secure for the app developer to use the industry standard protocol called OAuth which enables the user to give their consent for specific access without sharing their password. Most Google APIs support this OAuth standard, and starting today it is also available for the IMAP/SMTP feature of Gmail.

The feature is available in Google Code Labs and we have provided a site with documentation and sample code. In addition, Google has begun working with other companies like Yahoo and Mozilla on a formal Internet standard for using OAuth with IMAP/SMTP (learn more at the OAuth for IMAP mailing list).

One of the first companies using this feature is Syphir, in their SmartPush application for the iPhone, as shown in the screenshots below. Unlike other push apps, Sypher's SmartPush application never sees or stores the user’s Gmail password thanks to this new OAuth support.



We look forward to finalizing an Internet standard for using OAuth with IMAP/SMTP, and working with IMAP/SMTP mail clients to add that support.

2013, By: Seo Master

seo Coming soon: Gmail contextual gadgets available for trusted testers 2013

Seo Master present to you: At Campfire One this week we announced that we will soon open Gmail contextual gadgets as a new extension point for developers. These gadgets can smartly draw information from the web and let users perform relevant actions based on the content of an email message, all without leaving the Gmail inbox. For instance, contextual gadgets currently available in Gmail can detect links in emails to show previews of documents, videos, photos, and more, right inside the messages.

For businesses, Gmail contextual gadgets can boost employee productivity by complementing email in a context-specific and actionable way. Appirio, a cloud solution provider, provided a demonstration of the potential of Gmail contextual gadgets and other experimental features
with their new product PS Connect:



Soon we’ll be opening Gmail contextual gadgets as an extension for trusted testing by developers. If you have a good idea for this type of gadget today, please fill out this form. And for those of you who will be attending Google I/O in May, be sure to check out our session on building Gmail contextual gadgets.

2013, By: Seo Master
Powered by Blogger.