2011年5月28日土曜日

A Simple Windows Phone 7 MVVM Tombstoning Example

I have to admit Windows Phone 7 tombstoning had me in a bit of a muddle for
a while, so many places to store state, a confusing lifecycle and navigation
model. Most of the blog posts I read either detailed tombstoning for
non-MVVM applications, or described how to use or adapt an existing MVVM
framework for the purposes of tombstoning. I only really understood the
ins-and-outs of tombstoning after writing my own simple MVVM application. I
thought I would share this application here in this blog in the hope that it
might help other similarly confused developers!

What is tombstoning?

Mobile phones have limited resources compared to desktop computers, for that
reason most Smartphone OSs limit the number of applications that are
currently loaded into memory and executing. For Windows Phone 7 this limit
is one!

If the user hits the phone start button while you application is running,
the screen lock engages, or you invoke a chooser / launcher from your
application, then your application is terminated. However, when the user
navigates back to your app, the screen unlocks or the chooser / launcher
closed, the user expects to see your application again in its original
state.

To support this, the WP7 OS maintains state information which allows you to
'restore' your application by starting a new application instance and using
this state information to start the application in the same state as the one
which was terminated. For a full overview of this process I would recommend
reading the Execution Model Overview for Windows Phone on MSDN, or the three
part series on the Windows Phone Developer Blog (1), (2), (3).

This probably sounds like a lot of work, and to be honest, it is. You might
be wondering if the new multi-tasking capabilities that the Mango update
will bring (demoed at the MIX11 day 2 keynote and to be released probably
late 2012) will mean the that tombstoning will disappear. I have not seen
any official confirmation one way or the other, however, personally I think
you will still need to tombstone in Mango. It is most likely that the number
of concurrent applications will be limited and applications will still need
to tombstone as a result.

The Example Application

The example application I am using for this blog post is illustrated below.
The application displays a list of tweets, clicking on a tweet displays it
full screen. Twitter applications are the new Hello World!

The ViewModel

The view model is pretty trivial, each tweet is represented by a
FeedItemViewModel:

Collapse
public class FeedItemViewModel
{
public FeedItemViewModel()
{
}

public long Id { get; set; }

public string Title { get; set; }

public string Author { get; set; }

public DateTime Timestamp { get; set; }
}
The above view model does not change state, so there is no need to implement
INotifyPropertyChanged.

The top-level view model simply exposes a collection of the above feed
items. It also has an Update method which populates this list by querying
Twitter's search API for tweets that contain the #wp7 hashtag:

Collapse
public class FeedViewModel
{
// Twitter search for #WP7
private readonly string _twitterUrl =
"http://search.twitter.com/search.atom?rpp=100&&q=%23wp7";

private WebClient _webClient = new WebClient();

private readonly ObservableCollection<FeedItemViewModel> _feedItems =
new
ObservableCollection<FeedItemViewModel>();

public FeedViewModel()
{
_webClient.DownloadStringCompleted += WebClient_DownloadStringCompleted;
}

/// <summary>
/// Parses the response from our twitter request, creating a list of
FeedItemViewModelinstances
/// </summary>
private void WebClient_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
var doc = XDocument.Parse(e.Result);
var items = doc.Descendants(AtomConst.Entry)
.Select(entryElement => new FeedItemViewModel()
{
Title =
entryElement.Descendants(AtomConst.Title).Single().Value,
Id =
long.Parse(entryElement.Descendants(AtomConst.ID).Single().Value.Split(':')[2]),
Timestamp =
DateTime.Parse(entryElement.Descendants(AtomConst.Published).Single().Value),
Author =
entryElement.Descendants(AtomConst.Name).Single().Value
});

_feedItems.Clear();
foreach (var item in items)
{
_feedItems.Add(item);
}
}

/// <summary>
/// Gets the feed items
/// </summary>
public ObservableCollection<FeedItemViewModel> FeedItems
{
get { return _feedItems; }
}

/// <summary>
/// Gets a feed item by its Id
/// </summary>
public FeedItemViewModel GetFeedItem(long id)
{
return _feedItems.SingleOrDefault(item => item.Id == id);
}

/// <summary>
/// Update the feed items
/// </summary>
public void Update()
{
_webClient.DownloadStringAsync(new Uri(_twitterUrl));
}
}
The View

The FeedView page that is used to render the FeedViewModel (i.e the list of
tweets) is simply a NavigationList control (An ItemsControl optimised for
WP7 navigation scenarious) that has an ItemTemplate which renders each item:

Collapse
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<l:NavigationList x:Name="navigationControl"
ItemsSource="{Binding FeedItems}"
Navigation="NavigationList_Navigation">
<l:NavigationList.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical"
Height="100">
<TextBlock Text="{Binding Author}"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="{Binding Title}"
Margin="20,0,0,0"
Style="{StaticResource PhoneTextSmallStyle}"
TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</l:NavigationList.ItemTemplate>
</l:NavigationList>
</Grid>
The FeedItemView that is used to render the FeedItemViewModel is even
simpler:

Collapse
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Author}"
Style="{StaticResource PhoneTextLargeStyle}"
Foreground="{StaticResource PhoneAccentBrush}"/>
<TextBlock Text="{Binding Title}"
Style="{StaticResource PhoneTextLargeStyle}"
TextWrapping="Wrap"/>
</StackPanel>
</Grid>
Now that we have the ViewModels and their respective Views we need to bring
them together by making the ViewModel the DataContext for each View. There
are a number of different ways you can do this (Paul Stovell documents 8
different ways in his MVVM Instantiation Approaches blog post!), however, I
find the simplest approach with WP7 applications is to associated the
ViewModel with the application. Therefore, we add our view model as a
property of the App class and instantiate it when the Application_Launching
method (which handles the Launching lifecycle event) is invoked:

Collapse
public partial class App : Application
{

/// <summary>
/// Gets the ViewModel
/// </summary>
public FeedViewModel ViewModel { get; private set; }

...

private void Application_Launching(object sender, LaunchingEventArgs e)
{
ViewModel = new FeedViewModel();
ViewModel.Update();

// set the frame DataContext
RootFrame.DataContext = ViewModel;
}

...
}
The DataContext of the RootFrame is set to our 'top level' view model. The
RootFrame is an instance of PhoneApplicationFrame, which contains the
current PhoneApplicationPage instance, hence when you navigate from one page
to the next the content of the PhoneApplicationFrame is replaced within the
page that has been navigated to. As a result, each of your pages will
inherit the DataContext from the application frame.

Navigation

The DataContext of the RootFrame is inherited by the FeedView page, so once
the tweets are loaded they will be rendered in our NavigationList. In order
to navigate to a tweet when a user clicks on it we need to handle the
Navigation event:

Collapse
public partial class FeedView : PhoneApplicationPage
{
...

private void NavigationList_Navigation(object sender, NavigationEventArgs
e)
{
var selectedItem = e.Item as FeedItemViewModel;

// navigate to the feed items page
NavigationService.Navigate(new Uri("/FeedItemView.xaml?id=" +
selectedItem.Id, UriKind.Relative));
}

}
The above code uses the NavigationService to navigate to the FeedItemView
page. We use the querystring to pass the id of the selected tweet. We could
have passed this information from View the ViewModel by adding a
SelectedItemId property, however, we will find out later that there are some
advantages to using the querystring.

When the FeedItemView page is loaded we need to obtain this id from the
querystring and use it to locate the correct FeedItemViewModel instance.
This is done as follows:

Collapse
public partial class FeedItemView : PhoneApplicationPage
{
public FeedItemView()
{
InitializeComponent();
}

protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);

// parse the querystring to extract the id
long feedItemId = long.Parse(NavigationContext.QueryString["id"]);

// obtain this item from the view model.
this.DataContext = App.Current.ViewModel.GetFeedItem(feedItemId);
}
}
Tombstoning

With the above code our simple application works just fine, you can navigate
the list of tweets, click on one to see it in the FeedItemView page, then
use the back button to return to the original list of tweets. It would be
great if our job was complete at this point, however, the application fails
miserably if it is tombstoned. To test this, load the application, then hit
the start button, followed by the back button to return to the application.
This is what you are met with:

Tombstoning terminates the application, therefore the ViewModel and all the
state it contains is lost. Hence we return to an empty list.

So how do we fix this?

When your application gets tombstoned a Deactivated event is fired before
your application terminates, and when the user navigates back to your
application, a new instance is created an the Activated event is fired. The
Visual Studio WP7 application template helpfully adds event handlers for
these events on your App class.

Note that when an application is re-activated the Launching event is not
fired, therefore the code we added to construct a new view model is not
executed in this case.

The fix to this problem is rather simple, the framework provides a
PhoneApplicationService class which has a State property which allows you to
store your application state within a dictionary. The WP7 OS will persist
this dictionary of state on your behalf when your application is tombstoned.
You can place anything within this dictionary as long as it is serializable.
Therefore a simple solution to this problem is to simply place our view
model into this dictionary, retrieving it when the application is
re-activated:

Collapse
private readonly string ModelKey = "Key";

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
PhoneApplicationService.Current.State[ModelKey] = ViewModel;
}

private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (PhoneApplicationService.Current.State.ContainsKey(ModelKey))
{
ViewModel = PhoneApplicationService.Current.State[ModelKey] as
FeedViewModel;
RootFrame.DataContext = ViewModel;
}
}
With this simple change the application now returns to its previous state
when the user hits the back button. Note that this also works when the
application is tombstoned on the FeedItemView page:

This is because when the application is re-activated, the NavigationService
Journal which records the pages that have been visited is also restored. The
'back stack' contains the URI of each page which in our case contains the
query string which holds the Id of the tweet which is currently being
viewed.

Persisting State Between Sessions

In the above example, the application state was saved as tombstoned state.
But what if the user simply hits the back button until they navigate back
out of our application? In this context your application is closed, rather
than tombstoned. The PhoneApplicationService.Current.State dictionary which
we used to store our view model is not persisted in this context. For
long-term persistence you should save your data to the phones isolated
storage.

We can serialize our view model to isolated storage when the application
exits by adding code to the Application_Closing methods which handles the
Closing event. In the example below I am using the framework XmlSerializer,
which is the same serializer which is used to persist data in the
application state dictionary. However, as you have full control over
serialization, you might choose to use a serializer with better performance.

Collapse
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
// persist the data using isolated storage
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream("data.txt",
FileMode.Create,
FileAccess.Write,
store))
{
var serializer = new XmlSerializer(typeof(FeedViewModel));
serializer.Serialize(stream, ViewModel);
}
}
The code for launching the application now needs to be modified to first try
and load the data from isolated storage. If no data is found a new view
model is created:

Collapse
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// load the view model from isolated storage
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream("data.txt",
FileMode.OpenOrCreate, FileAccess.Read, store))
using (var reader = new StreamReader(stream))
{
if (!reader.EndOfStream)
{
var serializer = new XmlSerializer(typeof(FeedViewModel));
ViewModel = (FeedViewModel)serializer.Deserialize(reader);
}
}

// if the view model is not loaded, create a new one
if (ViewModel == null)
{
ViewModel = new FeedViewModel();
ViewModel.Update();
}

// set the frame DataContext
RootFrame.DataContext = ViewModel;
}
NOTE: This is no a fully functional twitter application, in a real
application you would probably want to update the data that is loaded from
isolated storage to add the latest tweets, however this blog post is about
tombstoning, not twitter application development!

Tombstoning UI state

So, now our application saves state during tombstoning and to isolated
storage when it exits. Surely we're all done now?

Well … almost.

If you start the application and scroll down the list of tweets, then hit
the start button, tombstoning the application, then hit the back button to
re-activate it our tweets are all there, but our list is scrolled back to
the top again:

Why is this? Well, when you simply navigate back to from one page within
your application to another, the original page is still present in memory
and as a result, any state held by the controls within the application UI is
maintained.

However, as we have seen already, when an application is tombstoned it is
terminated. The only state that remains is that which you manually place
into the State dictionary. Therefore, in order to maintain the scroll
location, which we should do, we need to determine its location and store it
in the tombstone state.

A while back I blogged about exposing a ScrollViewers scroll location as an
attached property in order to permit data binding. This approach could be
used here to bind the scroll location to a property on the view model.
However, in this case I think something a bit more lightweight is more
appropriate.

In the previous sections we have used the application-level code >
PhoneApplicationService.Current.State for storing tombstone state. You can
also store state on a page-level via the PhoneApplicationPage.State
property. This is a much more appropriate place for storing state relating
to UI controls within pages, rather than state which is more closely related
with your applications business logic.

It is still a little tricky to extract the required state information from
list controls. The code below uses Linq-to-VisualTree to locate the
VirtualizingStackPanel that can be used to get / set the scroll position.
The scroll location is placed in the State dictionary when the user
navigates away from the page.

Collapse
/// <summary>
/// Gets the NavigationList ItemsPanel
/// </summary>
private VirtualizingStackPanel ItemsPanel
{
get
{
return navigationControl.Descendants<VirtualizingStackPanel>()
.Cast<VirtualizingStackPanel>()
.SingleOrDefault();
}
}

private static readonly string ScrollOffsetKey = "ScrollOffsetKey";

protected override void
OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);

// persist the scroll position within the page state
var scroll = ItemsPanel;
if (scroll != null)
{
State[ScrollOffsetKey] = ItemsPanel.ScrollOwner.VerticalOffset;
}
}
Restoring this state is simply a matter of checking for the existence of
this key in the State dictionary when the page is navigated to:

Collapse
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);

// restore the scroll position
this.Loaded += (s, e2) =>
{
if (State.ContainsKey(ScrollOffsetKey))
{
var scroll = ItemsPanel;
if (scroll != null)
{
ItemsPanel.SetVerticalOffset((double)State[ScrollOffsetKey]);
}
}
};
}
Note that the state is restored after the Loaded event is fired because the
VirtualizingStackPanel which manages the scroll location is defined within
the NavigationList template and hence will not be present in the visual tree
when the page is not initially constructed (the same is true if you use a
ListBox as well).

Simple and Useful JavaScript Regular Expression Tutorial

Introduction

Regular Expression is a very important part of any language programming
because of its ability to help programmers to write fast and pure
applications.

You Don't Know What a Regular Expression Is?

A regular expression is an object that describes a pattern of characters.

Regular expressions are used to perform pattern-matching and
"search-and-replace" functions on text.

Web developer can also use Regular Expression in JavaScript. Now I describe
some simple examples of using Regular Expression in JavaScript.

The overall syntax should look like:

/pattern/modifiers

pattern specifies the search pattern
modifiers specify if our search should be case-sensitive, global, etc.
Modifiers Table

Modifier Description
i Perform case-insensitive matching
g Perform a global match (find all matches rather than stopping after the
first match)
m Perform multiline matching
To compile and use Regular Expression, you can use three useful functions.

Regular Expression Object Methods

Method Description
compile() Compiles a regular expression
exec() Tests for a match in a string. Returns the first match
test() Tests for a match in a string. Returns true or false
Example

Test sentence: Sometext sometext sometext

Expression Test Result
/sometext/ Sometext sometext sometext
/sometext/i Sometext sometext sometext
/sometext/g Sometext sometext sometext
/sometext/gi Sometext sometext sometext
/some/ Sometext sometext sometext
/some/i Sometext sometext sometext
/some/g Sometext sometext sometext
/some/ig Sometext sometext sometext

Javascript RSA Encryption and Java Decryption

Many of us have been working with Javascript since long time but when ever i
ask people how to send encrypted data, the only answer is to use SSL . But
this article shows how to send encrypted data even when we don't have ssl
enabled. This can come in to handy in many scenario's

I used jCryption and Javascript Library to encrypt in Javascript and
BouncyCastle Library on Javabackend to decypt,

Here is the flow in the example

First Generate RSA keys on server end ( Store in session).
Send public key to client (javascript)
Store keys in javascript variable
In All subsequent requests use this key to encrypt data and send to server
Use keys stored in session to decrypt data and send response to server
Keys generation utility class in Java

Collapse
package com.linkwithweb.encryption;

import java.io.IOException;
import java.security.KeyPair;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class EncryptionServlet
*/
public class EncryptionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public EncryptionServlet() {
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#service(HttpServletRequest request,
HttpServletResponse response)
*/
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {

if (request.getParameter("generateKeypair") != null) {

JCryptionUtil jCryptionUtil = new JCryptionUtil();

KeyPair keys = null;
if (request.getSession().getAttribute("keys") == null) {
keys = jCryptionUtil.generateKeypair(512);
request.getSession().setAttribute("keys", keys);
}

StringBuffer output = new StringBuffer();

String e = JCryptionUtil.getPublicKeyExponent(keys);
String n = JCryptionUtil.getPublicKeyModulus(keys);
String md = String.valueOf(JCryptionUtil.getMaxDigits(512));

output.append("{\"e\":\"");
output.append(e);
output.append("\",\"n\":\"");
output.append(n);
output.append("\",\"maxdigits\":\"");
output.append(md);
output.append("\"}");

output.toString();
response.getOutputStream().print(
output.toString().replaceAll("\r", "").replaceAll("\n",
"")
.trim());
} else {
response.getOutputStream().print(String.valueOf(false));
}
}

}
All client code is there in index.jsp and framework.js

Javascript Function that gets keys from server and stores in javascript
variable

Collapse
/**
* Get Security keys from server so that we can encrypt request in future
*/
function getKeys() {
$.jCryption.getKeys("EncryptionServlet?generateKeypair=true", function(
receivedKeys) {
keys = receivedKeys;
});
}
On login button clicked here is how you encrypt and send request to server

Collapse
/**
* Called on Login Button clicked
*/
function onLoginButtonClicked() {
var user = $("#login_user").val();
var password = $("#login_password").val();
$.jCryption.encrypt(user, keys, function(encrypted) {
encryptedUser = encrypted;
$.jCryption.encrypt(password, keys, function(encryptedPasswd) {
encryptedPassword = encryptedPasswd;
/**
* As both userName and password are encrypted now Submit login
*/
submitLoginRequest();
});
});
}

/**
* Submit Login request
*/
function submitLoginRequest() {
sendAjaxRequest("LoginServlet", {
username : encryptedUser,
password : encryptedPassword
}, function(data) {
if (data.length > 0) {
$("#login_status").empty();
$("#login_status").append(data);
}
});
}
And below is svn URL to download sample source code
https://linkwithweb.googlecode.com/svn/trunk/Utilities/jCryptionTutorial

Native x86 Android runtime will enable Android apps on Windows

A startup called BlueStacks has developed an Android runtime environment for
the Windows operating system. It will enable users to run Android
applications alongside conventional Windows software on Microsoft's
operating system. The technology impressed some major investors who have
supplied $7.6 million in Series A funding so that BlueStacks can turn its
software into a business.

As most Android application developers know, running Android software on a
Windows PC has historically involved emulation—which impairs performance and
adds considerably to resource overhead. BlueStacks has overcome the
performance barrier by building a native x86 Android runtime that doesn't
have to rely on emulation. The company says that Android applications
running on its stack will be highly responsive on Windows and won't suffer
from the kind of lag that developers are accustomed to experiencing when
using Google's emulator.

As some readers might remember, Canonical briefly explored some similar
concepts in 2009 but was never able to offer production-quality support for
Android software on Ubuntu. The Android userspace stack is somewhat insular
and not particularly conducive to application portability. BlueStacks
managed to overcome the obstacles with its own solution.

The BlueStacks runtime got its first public demonstration this week at the
Citrix Synergy conference. BlueStacks has made it possible for companies to
deliver Android applications through the Citrix Receiver. The partnership
with Citrix represents one of many ways in which the BlueStacks runtime can
be put to practical use.

To learn more about the underlying technology and the company's business
aspirations, I spoke over the phone with BlueStacks CEO Rosen Sharma. He
told me that the BlueStacks developers have worked to create a really
seamless experience for running Android applications on Windows. It offers
tight integration with the underlying platform—including mechanisms that
bridge the file systems, networking configuration, and notifications.

The BlueStacks runtime makes it possible for Android programs to run in
individual windows and be launched from shortcuts like any other standalone
Windows application. It also optionally offers the ability to run a complete
Android user experience on Windows, including the launcher and other
elements. Third-party applications that are built against the standard
Android APIs don't have to be recompiled in order to work with the
BlueStacks runtime. Users can even install conventional Android software
from Amazon's Android Appstore and run it on Windows.


Sharma says that BlueStacks is establishing relationships with hardware
manufacturers that are interested in shipping the x86 Android runtime on
consumer devices. He envisions mobile products that can offer the best of
both Android and Windows. One example would be a convertible netbook tablet
that normally runs Windows but switches to an Android interface for greater
touch-friendliness when the screen is flipped.


Such a product would offer the full power and multitasking capabilities of
Windows but also benefit from having access to Android's broad touch-enabled
software ecosystem. During my discussion with Sharma, he pointed out the
dominance of the iPad and the difficulty that hardware manufacturers are
facing as they try to compete. He said that BlueStacks could give them a way
to add value to their products and make them more competitive.

The company will announce its first hardware partners and OEM customers
within the next few weeks and could potentially have some demos to show on
prototype hardware at the upcoming Computex event. BlueStacks also intends
to offer a downloadable version of its runtime for regular end users. An
alpha release of the downloadable runtime could arrive as early as June or
July.

Mono for Android and MonoTouch status change

Anyone who keeps an ear to the Mono world will have doubtless heard of the
recent corporate changes that have impacted the Mono product line. For some
while Novell have owned Mono, having previously absorbed the original
developer, Miguel de Icaza, and his company, Ximian. Recently, Attachmate
completed their acquisition of Novell and there have been the usual
consequential streamlining processes occurring.

One of the casualties of this process is the Mono team, who were all
released. This means that formal development of the commercial tools
MonoTouch for iPhone development and Mono for Android for Android
development have now halted. There's been little noise on this subject from
Attachmate, but the current thinking is that people who've already bought
these products are still entitled to support. How supportive this support
turns out to be is, perhaps, questionable. Certainly the store mechanisms
that allow purchasing of MonoTouch and Mono for Android licenses have been
disabled.

I should just add at this point that these events should not affect Mono
itself, which is and always has been an open source platform. It's the
commercial tools for iOS and Android that are primarily affected.

For those who have been taking advantage of the homely feel of .NET
development for iOS and Android devices, this news has set the cat among the
pigeons, or thrown a spanner in the works, or whatever your preferred cliche
may be. However, all is not lost.

As soon as Miguel and his team were let go, they immediately set up Xamarin.
Xamarin is already working on producing API-compatible tools, similar to
MonoTouch and Mono for Android, currently named .NET for iOS and .NET for
Android respectively. The projected time for these tools is 3-4 months with
the iOS product coming first.

Clearly this 4 month gap may prove logistically troublesome for some, but if
you have already bought one of the Novell tools you can carry on working
with it with an eye to switching to the Xamarin equivalent towards the
Autumn.

If this time window is too much, well, you can always spend some time
picking up native Objective-C skills or learning Java and use the normal
development process in Xcode or AppCode for iOS, or Eclipse or IntelliJ IDEA
for Android.

It seems that interest in the Mono-based tools continues. Various scheduled
conference talks around the world on the topics are still going ahead rather
than being cancelled. Personally, I will still be talking on Mono for
Android at a Dutch User group (SDN) event in June.

That said, the timing of this unsettling news is not great for me as I'd
started work on a series of tutorials for Mono for Android. I'll probably
put them on hold until the Xamarin products show some life, but since I'd
finished the first one, I've put it on my web site. It's looks at how you
get going with Mono for Android and looks at the way Android applications
operate, to get you started in the Android world, from a Mono for Android
perspective.

http://tirania.org/blog/archive/2011/May-16.html

2011年5月27日金曜日

キーボード着脱式Androidタブレット「Eee Pad Transformer」フォトレビュー

 また、キーボードには、SDカードスロットとUSB 2.0×2というインターフェイスのほか、バッテリが内蔵されており、本体だけだと約9.5時間のバッテリ駆動時間が、約16時間に伸びる。このUSBについては、正確な対応機器リストはないが、同社担当者によると、マウスなどPCと同じ感覚で普通に使えるという。

 試用機のキーボードは日本語配列で、PCのように半角/全角キーや変換キーなどもあるが、これらがどのように機能するかは今回試せなかった。通常ファンクションキーがあるところは、ブラウザやメディア操作のホットキー、戻るキーなどがあり、ホームボタンも最下段にある。

 写真からわかる通り、タッチパッドもある。タッチパッドをなぞると「×」印のマウスカーソルが表示され、PCのようにアイコンなどをクリックできる。試用機では、右クリックは戻る機能が割り当てられていた。

 キーボードと組み合わせて持った感じは、ややずっしり来る。公称重量は約1.3kgで、手元で計ってもぴったり1,300gだった。内部密度が高いせいか、人によっては数値以上に重く感じるが、この重さは、一般的なモバイルノートよりも軽い。

 本体サイズは271×185×28mm(幅×奥行き×高さ)で、女性のカバンにも入るサイズに収まっている。

 タブレット単体では、サイズが271×177×12mm(同)、重量が約680gと、文字通り半分程度の薄さ、軽さになる。奥行きが縮むのは、ヒンジ部分が出っ張っているからだ。

 さきに、タブレットの見た目はほかの製品と大差ないと書いたが、それは正面からみた場合で、裏面は茶色く、鱗のようなテクスチャがあり、ワニ皮のような見た目と触り心地になっている。落ち着いた雰囲気で、高級感があるが、ここだけ見ると、女性の方がウケが良いかもしれない。

 重量はOptimus Pad(620g)とXOOM(700g)の中間ぐらい。やはりこれくらいの重量だと、ずっと把持していると、手首や腕が疲れる。ただ、当然ながらノートPCスタイルで使う時は、この重量が気になることはない。

 液晶パネルはIPSを採用しているため、視野角が広く、傾けても見やすいが、光沢があるので、蛍光灯などの反射はある。

 主な仕様は、CPUがNVIDIA Tegra 2(1GHz)、メモリ1GB、eMMC約32GB、1,280×800ドット表示/10点マルチタッチ対応10.1型IPS液晶を搭載。インターフェイスは、IEEE 802.11b/g/n無線LAN、Bluetooth 2.1+EDR、120万画素前面カメラ、500万画素背面カメラ、Mini HDMI出力、GPS、電子コンパス、光センサ、加速度センサ、ジャイロスコープなどを装備する。

m

キーボード着脱式Androidタブレット「Eee Pad Transformer」フォトレビュー

 ASUSTeK Computerが6月中旬に発売予定の、Android 3.0搭載タブレット「Eee Pad
Transformer TF 101」を限られた時間ながら借用することができたので、ここに写真で紹介したいと思う。

 まず、今回借りたのはプロトタイプであり、製品版では外観などが変更になる可能性がある。特にOSについては、製品版はAndroid 3.0が標準搭載で、追って同3.1へのアップグレードが予定され
ているが、プロトタイプでは2.2が搭載されていたので、画面はイメージと思って欲しい。なお、評価機にはAndroid 2.x用のハードウェアホームボタンなどがあるが、Android 3.0ではソフ
トウェアとなるため、このボタンはなくなる。

 本製品の最大の特徴は、専用の着脱式キーボードが付属する点。タブレット本体の見た目は、Optimus PadやXOOMなどと比べて大きく変わらないが、専用キーボードに取り付ける
と、クラムシェル型ノートPCと瓜二つの格好になる。実際にこのキーボードにはヒンジがあるので、ノートPC同様にたたんで持ち運ぶことができる。ちなみに、このヒンジ部分にはちょっとした仕掛けがあり、タブレットを開くと、ヒンジの接地部が回転とともに盛り上がり、奥から手前にかけて傾斜が付くようになっており、打鍵しやすいよう配慮されている。

AndroidStudyMemo (Resource)=Android hack wiki

http://www.android-hack.org/wiki/index.php/Frameworks/base/libs/ui

 

Frameworks/base/libs/ui

提供:Android hack wiki

移動: 案内, 検索

frameworks/base/libs/ui ディレクトリには UI 関連の native コードが含まれる。

このディレクトリにあるファイルは、libui というライブラリとして生成される。

TODO: このライブラリを使っているのは誰か?

EventHub : Input デバイス処理

Inputデバイスの処理

Android の Input デバイスの処理は、EventHub で行っている。ヘッダは include/ui/EventHub.h、実装コードは EventHub.cpp

参考: http://kobayuta.blog47.fc2.com/blog-entry-182.html

初期化処理

イベントの取得は EventHub::getEvent() で行うが、これが最初に呼ばれたときに初期化処理が行われる。初期化処理本体は EventHub::openPlatformInput() にある。

openPlatformInput() は、/dev/input ディレクトリをスキャンしてデバイスを見つける。

device_path (=/dev/input) を scan_dir() を使ってスキャンする。

デバイスが見つかると、open_device() を呼び出してデバイスをオープンする。

EventHub を使用している人

  • frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp
  • external/quake/standalone/main.cpp

 

User-Agentの中身を知るためのサイト

http://www.openspc2.org/JavaScript/library/system/useragent/index.html

 

Chromeブラウザの場合』下記のようにユーザーエージェントを返します。


ユーザーエージェント: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16 



ソースリスト(ポイント部分)
ユーザーエージェント:
<SCRIPT Language="JavaScript">
<!--
document.write(navigator.userAgent);
// -->
</SCRIPT>

WindowsMobile端末標準webブラウザのユーザーエージェント

端末

OS

ブラウザ

ユーザーエージェント

T-01A

WM6.1

InternetExplorer

モバイル

Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.0) T-01A

PC

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T-01A)

NFBrowser

-

Mozilla/5.0 (PDA; NF35WMPRO/3.2; like Gecko) NetFront/3.5 T-01A

WM6.5

InternetExplorer

モバイル

Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.0) T-01A_6.5

PC

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T-01A_6.5; Windows Phone 6.5)

NFBrowser

-

Mozilla/5.0 (PDA; NF35WMPRO/3.2; like Gecko) NetFront/3.5 T-01A_6.5

SC-01B

WM6.5

InternetExplorer

モバイル

Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.0) SC-01B

PC

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC-01B)

dynapocket T-01B

WM6.5

InternetExplorer

モバイル

Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.5) T-01B

PC

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T-01B; Windows Phone 6.5.3.5)

 

Android端末標準webブラウザのユーザーエージェント(その2)

端末

ファームウェア
バージョン
(ビルド番号)

ユーザーエージェント

HT-03A

Android 1.5

Mozilla/5.0 (Linux; U; Android 1.5; ja-jp; HT-03A Build/CDB72)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

Android 1.6

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; Docomo HT-03A Build/DRD08)
AppleWebKit/528.5+(KHTML, like Gecko) Version/3.1.2
Mobile Safari/ 525.20.1

Xperia™tm)
SO-01B

Android 1.6
(R1EA018)

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; SonyEricssonSO-01B Build/R1EA018)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

Android 1.6
(R1EA025)

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; SonyEricssonSO-01B Build/R1EA025)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

Android 1.6
(R1EA029)

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; SonyEricssonSO-01B Build/R1EA029)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

Android 2.1
(2.0.B.0.138)

Mozilla/5.0 (Linux; U; Android 2.1-update1; ja-jp; SonyEricssonSO-01B Build/2.0.B.0.138)
AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

Android 2.1
(2.0.1.B.0.19)

Mozilla/5.0 (Linux; U; Android 2.1-update1; ja-jp; SonyEricssonSO-01B Build/2.0.1.B.0.19)
AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

LYNX
SH-10B

Android 1.6

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; SH-10B Build/S7023)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

GALAXY S
SC-02B

Android 2.2

Mozilla/5.0 (Linux; U; Android 2.2; ja-jp; SC-02B Build/FROYO)
AppleWebKit/533.1(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

GALAXY Tab
SC-01C

Android 2.2

Mozilla/5.0 (Linux; U; Android 2.2; ja-jp; SC-01C Build/FROYO)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

LYNX 3D
SH-03C

Android 2.1

Mozilla/5.0 (Linux; U; Android 2.1-update1; ja-jp; SH-03C Build/SB110)
AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

REGZA Phone
T-01C

Android 2.1

Mozilla/5.0 (Linux; U; Android 2.1- update1; ja-jp; T-01C Build/TER018)
AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

Android 2.2

Mozilla/5.0 (Linux; U; Android 2.2.2; ja-jp; T-01C Build/FFR002)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

Optimus chat
L-04C

Android 2.2

Mozilla/5.0 (Linux; U; Android 2.2; ja-jp; L-04C Build/FRF91)
AppleWebKit/533.1 (KHTML,like Gecko) Version/4.0 Mobile Safari/533.1

MEDIAS
N-04C

Android 2.2
(A1010101)

Mozilla/5.0 (Linux; U; Android 2.2.1; ja-jp; N-04C Build/A1010101)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

Android 2.2
(A1010601)

Mozilla/5.0 (Linux; U; Android 2.2.1; ja-jp; N-04C Build/A1010601)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

Xperia™tm) arc
SO-01C

Android 2.3

Mozilla/5.0 (Linux; U; Android 2.3.2; ja-jp; SonyEricssonSO-01C Build/3.0.D.2.79)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

Optimus Pad
L-06C

Android 3.0

Mozilla/5.0 (Linux; U; Android 3.0.1; ja-jp; L-06C Build/HRI66)
AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13

AQUOS PHONE
SH-12C

Android 2.3

Mozilla/5.0 (Linux; U; Android 2.3.3; ja-jp; SH-12C Build/S5050)
AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

 

Android端末のUser Agent

Android端末のユーザーエージェント一覧です。

 機種名

キャリア

Androidバージョン

 ユーザーエージェント

 HT-03A

 DoCoMo

 1.5

 Mozilla/5.0 (Linux; U; Android 1.5; ja-jp; HT-03A Build/CDB72)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

 

 

 1.6

 Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; Docomo HT-03A Build/DRD08)
AppleWebKit/528.5+(KHTML, like Gecko) Version/3.1.2
Mobile Safari/ 525.20.1

 Xperia™tm)

 

 1.6

 Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; SonyEricssonSO-01B Build/R1EA018)
AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2
Mobile Safari/525.20.1

 HTC Desire

 SoftBank

 2.1

 Mozilla/5.0 (Linux; U; Android 2.1-update1; ja-jp; HTCX06HT Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

 IS01

Au 

1.6 

Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; IS01 Build/S6191) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 

 LYNX SH-10B

DoCoMo

1.6