2014년 9월 12일 금요일

Signing in with Google+ for Android

First step is to go to the Google Developers Console (https://console.developers.google.com/project) and create project as well as Client ID.



Second step would be adding some permissions in AndroidManifest.xml to access Google+ API, account name as part of sign in, OAuth 2.0 tokens or invalidate tokens to disconnect. The following permissions should be requested.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Now we're ready to add some codes to initialize GoogleApiClient.
Some might wonder what GoogleApiClient really does, it basically wraps a ServiceConnection to Google Play services, this GoogleApiClient object is used to communicate with Google+ API and becomes functional after the asynchronous connection has been established with the service, and typically GoogleApiClient is managed like this:
- initialize GoogleApiClient in Activity.onCreate()
- invoke GoogleApiClient.connect() during Activity.onStart()
- invoke GoolgeApiClient.disconnect() during Acitivity.onStop()


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.plus.Plus;

public class PlusActivity extends Activity 
        implements ConnectionCallbacks, OnConnectionFailedListener {

 /* Request code used to invoke sign in user interactions. */
 private static final int RC_SIGN_IN = 0;

 private GoogleApiClient mGoogleClient;

 private ProgressDialog mConnectionProgressDialog;

 /*
  * A flag indicating that a PendingIntent is in progress and prevents us
  * from starting further intents.
  */
 private boolean mIntentInProgress;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  mGoogleClient = new GoogleApiClient.Builder(this).addApi(Plus.API)
    .addScope(Plus.SCOPE_PLUS_LOGIN).addConnectionCallbacks(this)
    .addOnConnectionFailedListener(this).build();

  mConnectionProgressDialog = new ProgressDialog(this);
  mConnectionProgressDialog.setMessage("Signing in...");
 }

 @Override
 protected void onStart() {
  super.onStart();
  mGoogleClient.connect();
 }

 @Override
 protected void onStop() {
  super.onStop();

  if (mGoogleClient.isConnected()) {
   mGoogleClient.disconnect();
  }
 }

 @Override
 protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
  if (requestCode == RC_SIGN_IN) {
   mIntentInProgress = false;

   if (!mGoogleClient.isConnecting()) {
    mGoogleClient.connect();
   }
  }
 }

 @Override
 public void onConnectionFailed(ConnectionResult connectionResult) {
  Toast.makeText(this, "GoogleAPIClient Failed to Connect", Toast.LENGTH_SHORT).show();

  if (!mIntentInProgress && connectionResult.hasResolution()) {
   try {
    mIntentInProgress = true;
    startIntentSenderForResult(connectionResult.getResolution().getIntentSender(), RC_SIGN_IN, null, 0, 0, 0);
   } catch (SendIntentException e) {
    mIntentInProgress = false;
    mGoogleClient.connect();
   }
  }
 }

 @Override
 public void onConnected(Bundle bundle) {
  Toast.makeText(this, "GoogleAPIClient Connected", Toast.LENGTH_SHORT).show();
  mConnectionProgressDialog.dismiss();
 }

 @Override
 public void onConnectionSuspended(int arg0) {
  Toast.makeText(this, "GoogleAPIClient Connection Suspended", Toast.LENGTH_SHORT).show();
  mGoogleClient.connect();
 }
}

This is it, we done signing in Google+, will try to add some codes for accessing Google+ API to post some comments, retrieving friends list next time.





2014년 9월 10일 수요일

Add Maps to application (Google Maps)

The key class when working with a map object is the GoogleMap class, models the map object within application. Within UI, a map will be represented by either a MapFragment or MapView object.

Google Map handles the following operations automatically

  • connecting to the Google Maps service
  • downloading map tiles
  • displaying tiles on the device screen
  • displaying various controls such as pan & zoom
  • responding to pan & zoom gestures by moving the map and zooming in/out


Google Maps provides four types of maps: Normal, Hybrid, Satellite, Terrain.
To set the type of a map, use setMapType() of GoogleMap object.
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

Basic steps for adding a map to an Android application
1. Add a fragment
Add a <fragment> element to the Activity's layout file to define a Fragment object, and set android:name attribute to "com.google.android.gms.maps.MapFragment. This will attach a MapFragment to the Activity automatically.
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/map"
  android:name="com.google.android.gms.maps.MapFragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
We can also add a MapFragment to an Activity in code like the following:
mMapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.my_container, mMapFragment);
fragmentTransaction.commit();

2. Add map code
After setting the layout file as the content view for the Activity, get a handle to the map by calling findFragmentById() to set some initial options for the map.

mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

3. Verify map availability
Before interacting with a GoogleMap object, we need to make sure that an object can be instantiated.
Check the following example code snippets, this methods can be called from both onCreate() and onResume() to ensure that the map is always available.

private void setupMapIfNeeded() {
  // null check to confirm that the map has not been instantiated
  if (mGoolgeMap == null) {
    mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
    
    if (mGoogleMap != null) {
       // verified, it's ok to manipulate the map
    }
  }
}


2014년 9월 9일 화요일

Supporting different layouts & bitmaps

Create different layouts for each screen size you want to support to optimize user experience. Each layout file should be saved into the appropriate resource directory, named with a -<screen_size> suffix.

e.g.
My Project
       - res/
             - layout/                     ==> default portrait
                         main.xml
             - layout-land              ==> landscape
                         main.xml
             - layout-large/            ==> large portrait
                         main.xml
             - layout-large-land     ==> large landscape
                         main.xml

The file names must be exactly the same, but their contents are different in order to provide an optimized UI for the corresponding screen size.


Providing bitmap resources that are properly scaled to each of generalized densities: low, medium, high, etc. will help to achieve good graphical quality and performance on all screen densities.

To generate images, start with raw resources in vector format and generate the images for each density using the following size scales:

  • xxxhdpi: 4.0
  • xxhdpi: 3.0
  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (baseline)
  • ldpi: 0.75
If we generate a 200x200 image for xhdpi, we should generate the same resources in 150x150 for hdpi, 100x100 for mdpi, 300x300 for xxhdpi and then place them in the appropriate drawable resource directory:

e.g.

My Project
       - res/
             - drawable-xxhdpi/                  
                         example.png
             - drawable-xhdpi            
                         example.png
             - drawable-hdpi/
                         example.png
             - drawable-mdpi
                         example.png



Controlling App's Availability to Devices

Android supports a variety of features, some of them are hardware-based, some are software-based, and some are dependent on platform version. So app developer may need to control app's availability to devices based on app's required features.

We can restrict app's availability to devices through Google Play Store based on the following device characteristics:

  1. Device features
  2. Platform version
  3. Screen configuration

Device features:
Android defines feature IDs for any hardware or software feature that may not be available on all devices. So we can prevent users from installing app when their devices don't provide a given feature by declaring it with a <uses-feature> element in app's manifest file.

e.g. declaring the compass sensor as required
<uses-feature android:name="android.hardware.sensor.compass"
                       android:required="true" />

Google Play Store compares the features app requires to the features available on user's device to determine whether the app is compatible with each device. If the device does not provide all the features, the user cannot install the app.

In case device features are not required for running app's primary functionality, then set the required attribute to "false"  and check for device feature at runtime.
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
  // No compass available on this device, turn off the compass feature
  disableCompassFeature();
}


Platform version:
Different devices may run different versions of Android, which means new APIs of newer Android version may not be available on older versions of Android.

API level allows to declare the minimum version with which your app is compatible using <uses-sdk> element in app's manifest file.

e.g.
<uses-sdk android:minSdkVersion="14"
                 android:targetSdkVersion="19" />

minSdkVersion: declares the minimum version with which app is compatible
targetSdkVersion: declares the highest version on which app has been optimized

We can check the API level at runtime and gracefully degrade the corresponding features when the API level is too low.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
  // running on something older than API 11, so disable features
  disableSomeFeature();
}

Screen configuration:
Android runs on devices of various sizes from smart phones to TVs. In order to categorize devices by screen type, Android defines two characteristics for each devices: screen size (physical size) and screen density (DPI)

  • generalized sizes: small, normal, large and xlarge
  • generalized densities: mdpi (medium), hdpi, xhdpi (extra high), xxhdpi (extra-extra high)
By default most apps are compatible with all screen sizes and densities because the system makes all the adjustments to UI layout and image resources as necessary for each screen. However we can optimize the user experience for each screen configuration by adding specialized layouts for different screen sizes and optimized bitmap images for common screen densities.

For more information in detail, check the following developers site:



How to use ActionProvider Or ShareActionProvider

ActionProvider can generate action views for use in the action bar, dynamically populate submenus of a MenuItem, and handle default menu item invocations.

Two ways to use an action provider:
- Set the action provider on a MenuItem directly by calling setActionProvider (ActionProvider)
- Declare the action provider in an XML menu resource.   e.g.
  <item
    android:id="@+id/action_search"
    android:title="Search"
    android:icon="@drawable/search_icon"
    android:showasaction="ifRoom"
    android:actionproviderclass="com.my.CustomActionProvider" />

Making a custom action provider is straightforward, simply extend ActionProvider class and implement its callback methods as appropriate. It should be implemented like below code example:

public class MyCustomActionProvider extends ActionProvider {
   private Context mContext;
   private EditText mEditText;

   public MyCustomActionProvider (Context context) {
     super(context);
     mContext = context;
   }

   @override
   public View onCreateActionView() {
     // Make & return View that will be shown when action bar icon pressed
     // Here we have a custom layout that contains EditText for Search

     LayoutInflator layout = LayoutInflator.from(mContext);
     View view = layout.inflate(R.layout.search_layout, null);
     mEditText = (EditText) view.findViewById(R.id.edit_search);
     ...................
   }

   ................
}

public class MainActivity extends Activity {
  private MyCustomActionProvider mActionProvider;
  ...........

  @override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.items, menu);
    MenuItem item = menu.findItem(R.id.action_search);
    mActionProvider = (MyCustomActionProvider) item.getActionProvider();
    ..............
  }
  
  ...........
}

Android also provides an implementation of ActionProvider for Share actions: ShareActionProvider, which facilitates a share action by showing a list of possible apps for sharing directly in the action bar.
To add a share action with ShareActionProvider, just define the tag  for an <item> android:actionproviderclass="android.widget.ShareActionProvider".

The last step left to do is to define the Intent what we want to use for sharing. How we do it? just modify onCreateOptionMenu() method.
// In Activity#onCreateOptionsMenu
 public boolean onCreateOptionsMenu(Menu menu) {
     // Get the menu item.
     MenuItem menuItem = menu.findItem(R.id.my_menu_item);
     // Get the provider and hold onto it to set/change the share intent.
     mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
     // Set history different from the default before getting the action
     // view since a call to MenuItem.getActionView() calls
     // onCreateActionView() which uses the backing file name. Omit this
     // line if using the default share history file is desired.
     mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
     . . .
 }

 // Somewhere in the application.
 public void doShare(Intent shareIntent) {
     // When you want to share set the share intent.
     mShareActionProvider.setShareIntent(shareIntent);
 }

5. Project Scope Management (3)

5.3 Define Scope
Define Scope is the process of developing a detailed description of the project and product. The key benefit of this process is that it describes the product, service, or result boundaries by defining which of the requirements collected will be included in and excluded from the project scope.


Since all of the requirements identified in Collect Requirements may not be included in the project, the Define Scope process selects the final project requirements from the requirements documentation delivered during the Collect Requirements process. It then develops a detailed description of the project and product, service, or result.

The preparation of a detailed project scope statement is critical to project success and builds upon the major deliverables, assumptions, and constraints that are documented during project initiation. During project planning, the project scope is defined and described with greater specificity as more information about the project is known. Existing risks, assumptions, and constraints are analyzed for completeness and added or updated as necessary. The Define Scope process can be highly iterative. In iterative life cycle projects, a high-level vision will be developed for the overall project, but the detailed scope is determined one iteration at a time and the detailed planning for the next iteration is carried out as work progresses on the current project scope and deliverables.

Inputs
1) Scope management plan: a component of the project management plan that establishes the activities for developing, monitoring, and controlling the project scope.

2) Project charter: provides the high-level project description and product characteristics. It also contains project approval requirements. If a project charter is not used in the performing organization, then comparable information needs to be acquired or developed, and used as a basis for the detailed project scope management statement. Organizations that do not produce a formal project charter will usually perform an informal analysis to identify the content necessary for further scope planning.

3) Requirements documentation:  will be used to select the requirements that will be included in the project.

4) Organizational process assets: can influence how scope is defined
- Policies, procedures, and templates for a project scope statements;
- Project files from previous project; and
- Lessons learned from previous phrases or projects.

Tools & Techniques
1) Expert Judgment: used to analyze the information needed to develop the project scope statement. such judgement and expertise is applied to any technical detail.

2) Product Analysis: Each application area has one or more generally accepted methods for translating high-level product descriptions into tangible deliverables. Product analysis includes techniques such as product breakdown, systems analysis, requirements analysis, system engineering, value engineering, and value analsyis.

3) Alternatives Generation: used to develop as many potential options as possible in order to identify different approaches to execute and perform the work of the project. A variety of general management technique can be used, such as brainstorming, lateral thinking, analysis of alternatives, etc.

4) Facilitated Workshops: The participation of key players with a variety of expectations and/or fields of expertise in these intensive working sessions helps to reach a cross-functional and common understanding of the project objectives and its limits.

Outputs
1) Project Scope Statement: description of the project scope, major deliverables, assumptions, and constraints. The project scope statement documents the entire scope, including project and product scope. It describes, in detail, the project's deliverables and the work required to create those deliverables. It also provides a common understanding of the project scope among project stakeholders. It may contain explicit scope exclusions that can assist in managing stakeholder expectations. It enables the project team to peform more detailed planning, guides the project team's work during execution, and provides the baseline for evaluating whether requests for changes or additional work are contained within or outside the project's boundaries.

2) Project Document Updates: may be include
- Stakeholder register
- Requirements documentation and
- Requirements traceability matrix.



2014년 9월 2일 화요일

How to set/get Meta Data in AndroidManifest

In AndroidManifest.xml


Meta data defined in AndroidManifest.xml can be retrieved with some codes like this:

try {
    ApplicationInfo ai = getPackageManager().getApplicationInfo(activity.getPackageName(), PackageManager.GET_META_DATA);
    Bundle bundle = ai.metaData;
    String myApiKey = bundle.getString("com.myapp.version.api.key");
} catch (NameNotFoundException e) {
    Log.e(TAG, "Failed to load meta data : " + e.getMessage());
} catch (NullPointerException e) {
    Log.e(TAG, "Failed to load meta data : " + e.getMessage());         
}