package com.aliao.android.hipster; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; import com.actionbarsherlock.app.SherlockActivity; import java.io.File; import java.util.List; /** * Initial activity shown when the user has not yet signed up. Requires the user to enter their * user name and photo to sign up as a Hipster user. */ public class CheckInActivity extends SherlockActivity { // Action code used to launch the camera app and receive a photo in onActivityResult. private static final int TAKE_PHOTO_ACTION_CODE = 1000; // Regex to encourage people to use their full name. private static final String FULL_NAME_REGEX = "[a-zA-z]+([\\s'-][a-zA-Z]+)+"; // The file name passed to the camera for storing a photo taken by the user. private static final String USER_PHOTO_FILE_NAME = "user_photo.jpg"; // Key used by onSaveInstanceState for restoring the photo bitmap. public static final String SAVED_INSTANCE_BITMAP_KEY = "photoBitmap"; // View references. private EditText userNameEditText; private View photoFrame; private View retakePhotoButton; private View takePhotoLabel; private ImageView photoImageView; private ProgressBar progressBar; // Bitmap of the photo taken by the user for saving to the cloud. private Bitmap photoBitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If logged in, skip this activity and go directly to connect. if (isLoggedIn()) { startActivity(new Intent(this, ConnectActivity.class)); finish(); return; } // Set view layout and get view references. setContentView(R.layout.activity_checkin); userNameEditText = (EditText) findViewById(R.id.name); retakePhotoButton = findViewById(R.id.retake); takePhotoLabel = findViewById(R.id.take_photo_label); photoFrame = findViewById(R.id.photo_frame); photoImageView = (ImageView) findViewById(R.id.photo); progressBar = (ProgressBar) findViewById(android.R.id.progress); // Setup listeners. Button checkInButton = (Button) findViewById(R.id.check_in); checkInButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handleCheckIn(); } }); photoFrame.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handleTakePhoto(); } }); // When restoring the activity, make sure to restore the photo bitmap. if (savedInstanceState != null) { Bitmap photoBitmap = savedInstanceState.getParcelable(SAVED_INSTANCE_BITMAP_KEY); renderPhoto(photoBitmap); return; } // Show the rules dialog. This doesn't happen if the activity was restored. showRulesDialog(); } private boolean isLoggedIn() { HipsterPartyApp application = (HipsterPartyApp) getApplication(); HipsterUser currentUser = application.getUserActions().getCurrentUser(); return currentUser != null; } private void handleCheckIn() { String name = userNameEditText.getText().toString(); // Show a failure toast if the user didn't take a photo or enter a valid full name. int failureMessage = 0; if (photoBitmap == null) { failureMessage = R.string.messge_take_photo; } else if (TextUtils.isEmpty(name) || !name.matches(FULL_NAME_REGEX)) { failureMessage = R.string.message_enter_name; } if (failureMessage != 0) { Toast.makeText(CheckInActivity.this, getString(R.string.message_enter_name), Toast.LENGTH_SHORT).show(); return; } createUser(name); } private void handleTakePhoto() { // Launch an intent to open the camera app, if possible. Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri photoUri = Uri.fromFile(getPhotoFile()); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); if (canHandleIntent(this, cameraIntent)) { startActivityForResult(cameraIntent, TAKE_PHOTO_ACTION_CODE); return; } // No camera was available. Show an error dialog. AlertDialog.Builder builder = new AlertDialog.Builder(this) .setMessage(getString(R.string.error_photo_message)) .setPositiveButton(getString(R.string.not_hipster), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Exit the app when dismissing no camera message finish(); } }); builder.create(); } // Checks if there is a package that handles the intent. private boolean canHandleIntent(Context context, Intent intent) { final PackageManager packageManager = context.getPackageManager(); List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return !list.isEmpty(); } private void showRulesDialog() { // Show a dialog with ironic hipster rules message. AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle(R.string.rules_title) .setMessage(R.string.rules_details) .setPositiveButton(R.string.rules_confirmation, null /* no click listener needed */); builder.show(); } private File getPhotoFile() { // TODO(aliao): Handle no-external storage devices. return new File(Environment.getExternalStorageDirectory(), USER_PHOTO_FILE_NAME); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == TAKE_PHOTO_ACTION_CODE && resultCode == RESULT_OK) { loadPhotoFromCamera(); } } private void loadPhotoFromCamera() { String photoPath = getPhotoFile().getAbsolutePath(); // Get the dimensions of the photo frame view. int frameWidth = photoFrame.getWidth(); int frameHeight = photoFrame.getHeight(); // Get the dimensions of the bitmap. BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(photoPath, options); int bitmapWidth = options.outWidth; int bitmapHeight = options.outHeight; // Determine how much to scale down the image. int scaleFactor = Math.min(bitmapWidth / frameWidth, bitmapHeight / frameHeight); // Decode the image file into a Bitmap sized to fill the frame. options.inJustDecodeBounds = false; options.inSampleSize = scaleFactor; options.inPurgeable = true; Bitmap photoBitmap = BitmapFactory.decodeFile(photoPath, options); renderPhoto(photoBitmap); } private void renderPhoto(Bitmap newBitmap) { if (photoBitmap == newBitmap) { return; } // Make sure to recycle the old bitmap if the user took another picture. if (photoBitmap != null) { photoBitmap.recycle(); } photoBitmap = newBitmap; // Update the UI to display the new photo. if (newBitmap == null) { photoImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); photoImageView.setImageResource(R.drawable.hipster_user); retakePhotoButton.setVisibility(View.GONE); takePhotoLabel.setVisibility(View.VISIBLE); } else { photoImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); photoImageView.setImageBitmap(newBitmap); retakePhotoButton.setVisibility(View.VISIBLE); takePhotoLabel.setVisibility(View.GONE); } } @Override public void onSaveInstanceState(Bundle toSave) { super.onSaveInstanceState(toSave); toSave.putParcelable(SAVED_INSTANCE_BITMAP_KEY, photoBitmap); } private void createUser(final String name) { HipsterPartyApp application = (HipsterPartyApp) getApplication(); progressBar.setVisibility(View.VISIBLE); application.getUserActions().signUpAsync(name, photoBitmap, new HipsterActions.OnSignUpCallback() { @Override public void onSuccess(HipsterUser nextUser) { progressBar.setVisibility(View.GONE); Intent connectIntent = new Intent(CheckInActivity.this, ConnectActivity.class); startActivity(connectIntent); finish(); } @Override public void onError(Exception exception) { progressBar.setVisibility(View.GONE); Toast.makeText(CheckInActivity.this, exception.getMessage(), Toast.LENGTH_LONG).show(); } }); } }