Java tutorial
/** * Copyright 2015 Bob Zabor * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.stillnojetpacks.huffr.activities; import android.annotation.TargetApi; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.SoundPool; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.ShareActionProvider; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.ImageView; import com.stillnojetpacks.huffr.R; import java.util.HashMap; import java.util.Map; import java.util.Random; public class MainActivity extends AppCompatActivity implements SensorEventListener, SoundPool.OnLoadCompleteListener { public static final String TAG = "MainActivity"; public static final int SOUND_FILE_COUNT = 8; // arbitrary MAX of 8 private static final String KEY_PREF_SOUNDPOOL_MAX_STREAMS = "soundpoolMaxStreams"; private static final String KEY_PREF_USE_ALTERNATE_VERTICAL_SOUNDS = "useAlternateVerticalSounds"; private static final String KEY_PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD = "xHorizontalSensitivityThreshold"; private static final String KEY_PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD = "yVerticalSensitivityThreshold"; private int PREF_SOUNDPOOL_MAX_STREAMS; private boolean PREF_USE_ALTERNATE_VERTICAL_SOUNDS; private float PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD; private float PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD; private ImageView sprayButton; private SoundPool soundPool; private int sprayStreamId; private int capOffSoundId; private int spraySoundid; private int[] shakeVerticalSoundIds = new int[SOUND_FILE_COUNT]; private int[] shakeHorizontalSoundIds = new int[SOUND_FILE_COUNT]; private Map<Integer, Boolean> loaded = new HashMap<>(); private float lastX, lastY; private boolean sensorsInitialized; private SensorManager sensorManager; private Random random = new Random(); private ShareActionProvider shareActionProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setVolumeControlStream(AudioManager.STREAM_MUSIC); initializeToolbar(); initializeSprayButton(); sensorsInitialized = false; } @Override protected void onStart() { super.onStart(); loadPreferences(); initializeSoundPool(); loadSoundResources(); } @Override protected void onStop() { super.onStop(); if (sensorManager != null) { sensorManager.unregisterListener(this); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); MenuItem item = menu.findItem(R.id.action_share_app); shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_share_app) { share(); return true; } else if (id == R.id.action_rate_app) { rateApp(); return true; } else if (id == R.id.action_settings) { startActivity(new Intent(this, SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } @Override public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { Log.i(TAG, "SOUNDPOOL LOAD COMPLETE for sampleId:" + sampleId); loaded.put(sampleId, Boolean.TRUE); if (allSoundsLoaded()) { Log.i(TAG, "ALL SOUNDS LOADED! registering sensorManager"); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); if (accelerometer == null) { Log.i(TAG, "accelerometer is null"); } else { sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); } sprayButton.setEnabled(true); capOff(); } } private boolean allSoundsLoaded() { Log.i(TAG, "allSoundsLoaded: loaded size:" + loaded.size()); if (loaded.size() == SOUND_FILE_COUNT * 2 + 2) { Log.i(TAG, "allSoundsLoaded: loaded.containsValue(Boolean.FALSE):" + loaded.containsValue(Boolean.FALSE)); return !loaded.containsValue(Boolean.FALSE); } return false; } @Override public void onSensorChanged(SensorEvent event) { if (event.values == null) { return; } float x = event.values[0]; float y = event.values[1]; if (!sensorsInitialized) { lastX = x; lastY = y; sensorsInitialized = true; Log.i(TAG, "onSensorChanged: : SENSORS INITIALIZED"); } else { float deltaX = Math.abs(lastX - x); float deltaY = Math.abs(lastY - y); if (deltaX < PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD) deltaX = (float) 0.0; if (deltaY < PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD) deltaY = (float) 0.0; lastX = x; lastY = y; if (deltaY > deltaX) { shake("v"); } else if (deltaX > deltaY) { shake("h"); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void initializeToolbar() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(""); setSupportActionBar(toolbar); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window w = getWindow(); w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); // Set paddingTop of toolbar to height of status bar. toolbar.setPadding(0, getStatusBarHeight(), 0, 0); } } private int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void initializeSoundPool() { if (soundPool != null) { soundPool.release(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build(); soundPool = new SoundPool.Builder().setMaxStreams(PREF_SOUNDPOOL_MAX_STREAMS) .setAudioAttributes(audioAttributes).build(); } else { buildBeforeAPI21(); } soundPool.setOnLoadCompleteListener(this); } @SuppressWarnings("deprecation") private void buildBeforeAPI21() { soundPool = new SoundPool(PREF_SOUNDPOOL_MAX_STREAMS, AudioManager.STREAM_MUSIC, 0); } private void initializeSprayButton() { sprayButton = (ImageView) findViewById(R.id.sprayButton); sprayButton.setEnabled(false); sprayButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { startSpray(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { stopSpray(); } return false; } }); } private void loadPreferences() { PreferenceManager.setDefaultValues(this, R.xml.preferences, false); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); int newSoundpoolMaxSize = Integer.parseInt(sharedPref.getString(KEY_PREF_SOUNDPOOL_MAX_STREAMS, "4")); if (PREF_SOUNDPOOL_MAX_STREAMS != newSoundpoolMaxSize) { PREF_SOUNDPOOL_MAX_STREAMS = newSoundpoolMaxSize; initializeSoundPool(); } PREF_USE_ALTERNATE_VERTICAL_SOUNDS = sharedPref.getBoolean(KEY_PREF_USE_ALTERNATE_VERTICAL_SOUNDS, false); PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD = sharedPref.getInt(KEY_PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD, 50) / 10.0f; PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD = sharedPref.getInt(KEY_PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD, 31) / 10.0f; Log.i(TAG, "loadPreferences. PREF_SOUNDPOOL_MAX_STREAMS:" + PREF_SOUNDPOOL_MAX_STREAMS); Log.i(TAG, "loadPreferences. PREF_USE_ALTERNATE_VERTICAL_SOUNDS:" + PREF_USE_ALTERNATE_VERTICAL_SOUNDS); Log.i(TAG, "loadPreferences. PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD:" + PREF_X_HORIZONTAL_SENSITIVITY_THRESHOLD); Log.i(TAG, "loadPreferences. PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD:" + PREF_Y_VERTICAL_SENSITIVITY_THRESHOLD); } private void loadSoundResources() { for (int i = 0; i < SOUND_FILE_COUNT; i++) { String verticalShakeresourceName = PREF_USE_ALTERNATE_VERTICAL_SOUNDS ? "shake_v_a" + i : "shake_v_b" + i; String horizontalShakeresourceName = "shake_h_" + i; shakeVerticalSoundIds[i] = soundPool.load(this, getResources().getIdentifier(verticalShakeresourceName, "raw", "com.stillnojetpacks.huffr"), 1); shakeHorizontalSoundIds[i] = soundPool.load(this, getResources().getIdentifier(horizontalShakeresourceName, "raw", "com.stillnojetpacks.huffr"), 1); loaded.put(shakeVerticalSoundIds[i], Boolean.FALSE); loaded.put(shakeHorizontalSoundIds[i], Boolean.FALSE); } spraySoundid = soundPool.load(this, R.raw.spray, 1); capOffSoundId = soundPool.load(this, R.raw.cap_off, 1); loaded.put(spraySoundid, Boolean.FALSE); loaded.put(capOffSoundId, Boolean.FALSE); } private void shake(@NonNull String axis) { int nextSoundId = "v".equals(axis) ? shakeVerticalSoundIds[random.nextInt(SOUND_FILE_COUNT)] : shakeHorizontalSoundIds[random.nextInt(SOUND_FILE_COUNT)]; soundPool.play(nextSoundId, 1.0f, 1.0f, 1, 1, 1.0f); } private void capOff() { soundPool.play(capOffSoundId, 1.0f, 1.0f, 1, 0, 1.0f); } private void startSpray() { sprayStreamId = soundPool.play(spraySoundid, 0.65f, 0.65f, 2, -1, 1.0f); } private void stopSpray() { soundPool.stop(sprayStreamId); } private void share() { if (shareActionProvider != null) { String message = "huffr turns your android into a can of spray paint: " + uriForUrl("market://details"); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, message); shareIntent.setType("text/plain"); shareActionProvider.setShareIntent(shareIntent); } } private void rateApp() { try { Intent rateIntent = rateIntentForUrl("market://details"); startActivity(rateIntent); } catch (ActivityNotFoundException e) { Intent rateIntent = rateIntentForUrl("http://play.google.com/store/apps/details"); startActivity(rateIntent); } } @SuppressWarnings("deprecation") @TargetApi(Build.VERSION_CODES.LOLLIPOP) private Intent rateIntentForUrl(String url) { Intent intent = new Intent(Intent.ACTION_VIEW, uriForUrl(url)); int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT; } else { flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET; } intent.addFlags(flags); return intent; } private Uri uriForUrl(String url) { return Uri.parse(String.format("%s?id=%s", url, getPackageName())); } }