Java tutorial
/******************************************************************************* * Copyright (c) 2012 rob@theultimatelabs.com. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * rob@theultimatelabs.com - initial API and implementation ******************************************************************************/ package com.theultimatelabs.scale; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.speech.RecognizerIntent; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.google.ads.AdRequest; import com.google.ads.AdSize; import com.google.ads.AdView; public class ScaleActivity extends Activity implements OnInitListener { public final static String TAG = "ScaleActivity"; public final static String PREFS = "PREFS"; private SharedPreferences mSettings; private TextToSpeech mTts; private JSONObject mDensitiesJson; private JSONObject mVolumesJson; private JSONObject mWeightsJson; private final double OUNCES_IN_GRAMS = 28.3495; private double mWeightGrams; private double mZeroGrams = 0; private double mUnitsRatio = 1.0; private String mUnitsText = "grams"; private TextView mUnitsView; private AdView adView = null; private LinearLayout adLayout; private TextView mWeightTextView; private TextView disableAdsText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.scale); Log.v(TAG, "onCreate"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mSettings = getSharedPreferences(PREFS, 0); mUnitsText = mSettings.getString("unitsText", "grams"); mUnitsRatio = mSettings.getFloat("unitsRatio", (float) 1.0); mTts = new TextToSpeech(this, this); mUnitsView = (TextView) findViewById(R.id.text_unit); mUnitsView.setText(mUnitsText); findViewById(R.id.text_unit).setOnClickListener(new OnClickListener() { public void onClick(View v) { while (mTts.isSpeaking()) ; Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say Units"); startActivityForResult(intent, 0); if (adView != null) { adView.loadAd(new AdRequest()); } } }); mWeightTextView = (TextView) findViewById(R.id.text_weight); mWeightTextView.setText("00.00"); /* * TextPaint weightTextPaint = mWeightTextView.getPaint(); CharSequence * weightText = mWeightTextView.getText(); while (weightText != * TextUtils.ellipsize(weightText, weightTextPaint, * getWindowManager().getDefaultDisplay * ().getWidth()*2/3,TextUtils.TruncateAt.END)) { * weightTextPaint.setTextSize(weightTextPaint.getTextSize() - 1); } */ mWeightTextView.setOnClickListener(new OnClickListener() { public void onClick(View v) { Toast.makeText(getApplicationContext(), "Zero'd", Toast.LENGTH_LONG).show(); mZeroGrams = mWeightGrams; if (adView != null) { adView.loadAd(new AdRequest()); } } }); mWeightTextView.setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View v) { mZeroGrams = 0; Toast.makeText(getApplicationContext(), "Reset", Toast.LENGTH_LONG).show(); if (adView != null) { adView.loadAd(new AdRequest()); } return true; } }); disableAdsText = (TextView) findViewById((R.id.text_disableAds)); disableAdsText.setOnClickListener(new OnClickListener() { public void onClick(View v) { new AlertDialog.Builder(ScaleActivity.this).setTitle("Keep Software Free and Open Source") .setMessage("Ads help support further development, but they are OPTIONAL." + " If you choose to disable ads, please consider donating. All dontations" + " go towards purchasing hardware for open source development. " + "Disabling ads or donating will not change the features availble in this app." + " Thank you. rob@theultimatelabs.com") .setPositiveButton("Disable Ads", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { adLayout.removeAllViews(); adView.removeAllViews(); disableAdsText.setVisibility(View.INVISIBLE); mSettings.edit().putBoolean("ads", false).commit(); adView = null; } }).setCancelable(true).setNegativeButton("Keep Ads", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }).setNeutralButton("Disable Ads + Donate", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { adLayout.removeAllViews(); adView.removeAllViews(); disableAdsText.setVisibility(View.INVISIBLE); mSettings.edit().putBoolean("ads", false).commit(); adView = null; startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://blog.theultimatelabs.com/p/donate.html"))); } }).show(); } }); TextView aboutText = (TextView) findViewById((R.id.text_about)); aboutText.setOnClickListener(new OnClickListener() { public void onClick(View v) { startActivity(new Intent(getApplicationContext(), AboutActivity.class)); } }); /* * .setMessage() new AlertDialog.Builder(this) .setMessage(mymessage) * .setTitle(title) .setCancelable(true) * .setNeutralButton(android.R.string.cancel, new * DialogInterface.OnClickListener() { public void * onClick(DialogInterface dialog, int whichButton){} }) .show(); }} */ // / mDensitiesJson = loadJsonResource(R.raw.densities); mVolumesJson = loadJsonResource(R.raw.volumes); mWeightsJson = loadJsonResource(R.raw.weights); // Initiate a generic request to load it with an ad if (mSettings.getBoolean("ads", true)) { // Create the adViewj adView = new AdView(this, AdSize.SMART_BANNER, "a15089dfb39c5a8"); // Log.w(TAG, new Integer(R.id.layout_ads).toString()); adLayout = (LinearLayout) findViewById(R.id.layout_ads); // Add the adView to it adLayout.addView(adView, 0); disableAdsText.setVisibility(View.VISIBLE); } else { disableAdsText.setVisibility(View.INVISIBLE); adView = null; } Intent intent = getIntent(); mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); findScale(); } @Override public void onDestroy() { super.onDestroy(); if (adView != null) { adView.destroy(); } if (mTts != null) { mTts.stop(); mTts.shutdown(); } } public JSONObject loadJsonResource(int id) { InputStream stream = getResources().openRawResource(id); byte[] buffer; try { buffer = new byte[stream.available()]; int bytesRead = stream.read(buffer); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } JSONObject json; try { json = new JSONObject(new String(buffer)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } return json; } @Override public void onStart() { super.onStart(); if (adView != null) { adView.loadAd(new AdRequest()); } Log.v(TAG, "onStart"); } @Override protected void onStop() { super.onStop(); // Log.v(TAG,"onStop"); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.scale, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { Log.i(TAG, String.format("item selected %s", item.getTitle())); return true; } private UsbDevice mDevice; public void findScale() { if (mDevice == null) { UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while (deviceIterator.hasNext()) { mDevice = deviceIterator.next(); Log.v(TAG, String.format( "name=%s deviceId=%d productId=%d vendorId=%d deviceClass=%d subClass=%d protocol=%d interfaceCount=%d", mDevice.getDeviceName(), mDevice.getDeviceId(), mDevice.getProductId(), mDevice.getVendorId(), mDevice.getDeviceClass(), mDevice.getDeviceSubclass(), mDevice.getDeviceProtocol(), mDevice.getInterfaceCount())); break; } } if (mDevice != null) { new ScaleListener().execute(); } else { new AlertDialog.Builder(ScaleActivity.this).setTitle("Scale Not Found") .setMessage("Please connect scale with OTG cable and turn the scale on").setCancelable(false) .setPositiveButton("Try Again", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { findScale(); } }).setNegativeButton("Close", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }).setNeutralButton("Buy Scale", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://theultimatelabsstore.blogspot.com/p/store.html")); startActivity(browserIntent); } }).show(); } } private class ScaleListener extends AsyncTask<Void, Double, Void> { private byte mLastStatus = 0; private double mLastWeight = 0; @Override protected Void doInBackground(Void... arg0) { byte[] data = new byte[128]; int TIMEOUT = 2000; boolean forceClaim = true; Log.v(TAG, "start transfer"); UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); if (mDevice == null) { Log.e(TAG, "no device"); return null; } UsbInterface intf = mDevice.getInterface(0); Log.v(TAG, String.format("endpoint count = %d", intf.getEndpointCount())); UsbEndpoint endpoint = intf.getEndpoint(0); Log.v(TAG, String.format("endpoint direction = %d out = %d in = %d", endpoint.getDirection(), UsbConstants.USB_DIR_OUT, UsbConstants.USB_DIR_IN)); UsbDeviceConnection connection = usbManager.openDevice(mDevice); Log.v(TAG, "got connection:" + connection.toString()); connection.claimInterface(intf, forceClaim); while (true) { int length = connection.bulkTransfer(endpoint, data, data.length, TIMEOUT); if (length != 6) { Log.e(TAG, String.format("invalid length: %d", length)); return null; } byte report = data[0]; byte status = data[1]; byte exp = data[3]; short weightLSB = (short) (data[4] & 0xff); short weightMSB = (short) (data[5] & 0xff); // float weight = ((float)weightLSB+weightMSB*255)/10; //Log.v(TAG, String.format("report=%x status=%x exp=%x lsb=%x msb=%x", report, status, exp, weightLSB, weightMSB)); if (report != 3) { Log.v(TAG, String.format("scale status error %d", status)); return null; } double weightOunces = (weightLSB + weightMSB * 255) / 10; //Log.v(TAG, "ounces:" + weightOunces); mWeightGrams = weightOunces * OUNCES_IN_GRAMS; //Log.v(TAG, "grams:" + mWeightGrams); double zWeight = (mWeightGrams - mZeroGrams) * mUnitsRatio; // if (mLastStatus != status) { switch (status) { case 1: Log.w(TAG, "Scale reports FAULT!\n"); break; case 3: Log.i(TAG, "Weighing..."); if (mLastWeight != zWeight) { // Math.abs(mLastWeight-weight) // // >= .5) { publishProgress(zWeight); } break; case 2: case 4: if (mLastWeight != zWeight) { Log.i(TAG, String.format("Final Weight: %f", zWeight)); publishProgress(zWeight); } break; case 5: Log.w(TAG, "Scale reports Under Zero"); if (mLastWeight != zWeight) { publishProgress(0.0); } break; case 6: Log.w(TAG, "Scale reports Over Weight!"); break; case 7: Log.e(TAG, "Scale reports Calibration Needed!"); break; case 8: Log.e(TAG, "Scale reports Re-zeroing Needed!\n"); break; default: Log.e(TAG, "Unknown status code"); break; } mLastWeight = zWeight; mLastStatus = status; // } } } @Override protected void onProgressUpdate(Double... weights) { Double weight = weights[0]; Log.i(TAG, "update progress"); String weightText = String.format("%.2f", weight); Log.i(TAG, weightText); mWeightTextView.setText(weightText); mWeightTextView.invalidate(); if (weight == 0.0) { mTts.speak("zero'd", TextToSpeech.QUEUE_FLUSH, null); } else { mTts.speak(weightText + mUnitsText, TextToSpeech.QUEUE_FLUSH, null); } } @Override protected void onPostExecute(Void result) { Toast.makeText(getApplicationContext(), "Scale Disconnected", Toast.LENGTH_LONG).show(); mDevice = null; finish(); } } double findMatch(ArrayList<String> matches, JSONObject json, StringBuilder outName) { // Find type for (String match : matches) { Iterator<String> unitNames = json.keys(); Log.v(TAG, "match: " + match); while (unitNames.hasNext()) { String unitName = unitNames.next(); String unitNameNotPlural = unitName.substring(0, unitName.length() - 1); Log.v(TAG, "name: " + unitName); if (match.contains(unitName) || match.contains(unitNameNotPlural)) { double unit = json.optDouble(unitName, 0); Log.i(TAG, String.format("MATCH!: %s %f", unitName, unit)); outName.append(unitName); return unit; } } } return 0; } /* * protected void onPostResume() { TextPaint unitPaint = * mUnitsView.getPaint(); CharSequence unitText = mUnitsView.getText(); * Log.e(TAG,String.format("%d %d %d",mUnitsView.getMaxHeight(),mUnitsView. * getMaxWidth(),getWindowManager().getDefaultDisplay().getWidth())); * //while (unitText != TextUtils.ellipsize(unitText, unitPaint, * mUnitsView.getMaxEms(),TextUtils.TruncateAt.END)) { // * unitPaint.setTextSize(unitPaint.getTextSize() - 1); //+} } */ protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.v(TAG, "GOT SPEECH RESULT " + resultCode + " req: " + requestCode); if (resultCode == RESULT_OK) { ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); Log.i(TAG, "Check for density"); StringBuilder densityName = new StringBuilder(); double density = findMatch(matches, mDensitiesJson, densityName); Log.i(TAG, "Check for volume"); StringBuilder volumeName = new StringBuilder(); double volume = findMatch(matches, mVolumesJson, volumeName); Log.i(TAG, "Check for weight"); StringBuilder weightName = new StringBuilder(); double weight = findMatch(matches, mWeightsJson, weightName); if (density != 0 && volume != 0) { mUnitsRatio = 1000.0 / density / volume; mUnitsText = String.format("%s of %s", volumeName, densityName); } else if (weight != 0) { mUnitsRatio = 1.0 / weight; mUnitsText = String.format("%s", weightName); } else { Toast.makeText(this, "Does not compute", Toast.LENGTH_LONG).show(); mTts.speak("Does not compute", TextToSpeech.QUEUE_FLUSH, null); } Editor settingsEditor = mSettings.edit(); mUnitsView.setText(mUnitsText); settingsEditor.putString("unitsText", mUnitsText); settingsEditor.putFloat("unitsRatio", (float) mUnitsRatio); settingsEditor.commit(); } super.onActivityResult(requestCode, resultCode, data); // startActivity(new Intent(Intent.ACTION_VIEW, // Uri.parse("http://www.youtube.com/watch?v=2qBgMmRMpOo"))); } public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { mTts.setLanguage(Locale.US); mTts.setPitch(.9f); } else { Log.e(TAG, "TTS Initilization Failed!"); } // TODO Auto-generated method stub } }