Drawing buttons at different times - Android Q&A, Help & Troubleshooting

I am having a problem with my first Android app. I am posting here looking for guidance to find a solution, or to decide if maybe what I am attempting is to bothersome for someone just learning the android platform. My Java and OO are very strong though.
I am writing a calculator app as my first android app.
I have a mode button on the calculator that changes the buttons to make new functions available.
When mode switches, certain buttons get changed to a different drawable with different colors, and all the text gets updated on all the buttons.
Each mode has a new string array corresponding to the text for that mode.
What I am currently trying to achieve is having a delay between the time that each button is updated, a sort of cascade effect. I have not successfully implemented this.
In the following code I have a toggleLabels method which attempts to do this. It has three if blocks corresponding to the three modes, which each gets a new set of text and buttons. There are two nested for loops in each running i=width and j=height.
To create the cascade effect I grabbed system time, and then subtracted from current time to see that 100ms had passed.
No cascade effect takes place, and when I hit the mode button, there is a long delay then all of the buttons switch at once. The delay seems to be exactly 2 seconds, which corresponds to the cumulative delay of 100ms per button X 20 buttons.
I also tried an alternate method of Thread.Sleep() which yielded the same result, and which I read was bad practice to implement in your UI thread.
Basically I am doing..
loop through each button
{
Change button drawable
Change button text
delay X time
}
But what is showing in the app is
loop through each button
{
Change button drawable
Change button text
}
delay (X * N buttons) amount of time
draw all the buttons at once
I
After doing a lot of investigating, and not finding to much relevant info out there, I am thinking I need to implement a new thread to do this in.
I also came up with the idea of extending a new class of button and overriding the ondraw method with a delay in it. Not sure this is a horribly improper way of doing it.
My code is as follows....
Code:
package com.example.calculator;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
EditText displayUpper;
EditText displayLower;
//View root;
LinearLayout keyPanel;
Button[][] buttons;
int width;
int height;
String[] labels1;
String[] labels2;
String[] labels3;
int mode;
long time;
boolean click;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
width=4;
height=5;
mode=3;
click=false;
// root = (LinearLayout)findViewById(R.id.root);
keyPanel = (LinearLayout)findViewById(R.id.keyPanel);
displayUpper = (EditText)findViewById(R.id.editText1);
displayLower = (EditText)findViewById(R.id.editText1);
labels1=getResources().getStringArray(R.array.first_panel);
labels2=getResources().getStringArray(R.array.second_panel);
labels3=getResources().getStringArray(R.array.third_panel);
assignButtons(); //<-must come before toggleLabel
toggleLabel(); //<-must come after assignButtons
final Runnable r = new Runnable()
{
public void run()
{
toggleLabel();
}
};
buttons[3][0].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
r.run();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//---This method stores all the buttons in a multi-dimensional array
//--- Assigns buttons starting at left column from top to bottom
private void assignButtons()
{
buttons=new Button[width][height];
LinearLayout temp;
for(int i=0;i<width;i++)
{
temp = (LinearLayout)keyPanel.getChildAt(i);
for(int j=0;j<height;j++)
{
buttons[i][j] = (Button)temp.getChildAt(j);
}
}
}
//--This method set and toggles all the button labels
private void toggleLabel()
{
int pos=0;
boolean notchange=true;
if(mode==0)//<--If mode=0 change to second set of buttons
{
mode=1;
time=System.currentTimeMillis();
for(int i=0;i<width;i++)
{
for(int j=0;j<height;j++)
{
notchange=true;
while(notchange)
{
if(System.currentTimeMillis()-time>100)
{
notchange=false;
buttons[i][j].setText(labels2[pos]);
pos++;
if(i==3||j==0)
{
buttons[i][j].setBackgroundResource(R.drawable.sec_button);
}
time=System.currentTimeMillis();
}
}
}
}
}
else if(mode==1)//<--If mode=1 change to third set of buttons
{
mode=2;
time=System.currentTimeMillis();
for(int i=0;i<width;i++)
{
for(int j=0;j<height;j++)
{
notchange=true;
while(notchange)
{
if(System.currentTimeMillis()-time>100)
{
notchange=false;
buttons[i][j].setText(labels3[pos]);
pos++;
if(i==3||j==0)
{
buttons[i][j].setBackgroundResource(R.drawable.third_button);
}
time=System.currentTimeMillis();
}
}
}
}
}
else//<--else change back to first set of buttons
{
mode=0;
time=System.currentTimeMillis();
for(int i=0;i<width;i++)
{
for(int j=0;j<height;j++)
{
notchange=true;
while(notchange)
{
if(System.currentTimeMillis()-time>100)
{
notchange=false;
buttons[i][j].setText(labels1[pos]);
pos++;
if(i==3||j==0)
{
buttons[i][j].setBackgroundResource(R.drawable.calcbutton);
}
time=System.currentTimeMillis();
}
}
}
}
}
}
}

Does anyone have any input on this?

Related

Help: reading out sensor data

Hi folks,
well ... first of all: I'm completely new to programming related to Android. I do have basic knowledge in programming with Basic and C. But im all new to Java and programming with the Android ecosystem (I am familiar with the Android ecosystem, though ... I've just never written code for Android).
Now I wanted a simple app to read out and display some sensor data, such as acceleration along y-axis and rotation angle around y-axis.
But I found the whole way you get stuff out of the sensors very confusing ans somehow unnecessarily complicated. However....
I've successfully managed to code an app, that checks whether certain sensors are available or not - and show an according text in a TextView for the user to read.
The next step was, I wanted to code an app that reads the rotation angle and shows the current angle in a TextView for the user. But I haven't managed that.
I found the whole System of reading the rotation data very complex..... why isn't there just a simple function like "get the y-axis rotation angle" and thats it .... I've searched a lot in the Interwebz, tried to understand how that stuff works, and used some code of some examples i thought i understood ... well, I obviously didn't ....
This is what I've got so far:
Code:
package test.sensor4;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
//float A[] = new float[9];
//float I[] = new float[9];
float[] mGravity;
float[] mGeomagnetic;
float azimut;
float pitch;
float roll;
Button btn1;
TextView tv1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
btn1 = (Button)findViewById(R.id.button1);
btn1.setOnClickListener(this);
//SensorManager.registerListener(this)
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float A[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(A, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(A, orientation);
azimut = orientation[0]; // orientation contains: azimut, pitch and roll
pitch = orientation[1];
roll = orientation[2];
TextView tv1 = (TextView)findViewById(R.id.text1);
tv1.setText(String.valueOf(+roll));
}
}
}
@Override
public void onClick(View e) {
TextView tv2 = (TextView)findViewById(R.id.text2);
tv2.setText(String.valueOf(+pitch));
}
}
what this does is: it doesn't change the text from the first textview at all ... in the second textview it prints "0.0"
I don't understand why .... Maybe you guys can help me.
Thanks in advance.
Best wishes.

A Journey Through HMS Awareness - Part 1

HUAWEI Awareness Kit provides your app with the ability to obtain contextual information including users' current time, location, behavior, audio device status, ambient light, weather, and nearby beacons.
There are two types of API in awareness Kit - Capture API and Barrier API. The Capture API allows the app to request the current user status and the Barrier API allows the app to set a combination of contextual conditions. In this article we are explaining about Location Awareness, Headset Awareness, Ambient Light Awareness and Bluetooth Car Stereo Awareness.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Steps for developing capture capabilities
1. Obtain the Capture Client object of HUAWEI Awareness Kit.
2. Call the respective query capability API through the Capture Client object to obtain the user's context.
3. Enable your app to listen for the result returned by HUAWEI Awareness Kit for further processing.
Steps for developing barrier capabilities
1. Define the barrier.
2. Define PendingIntent that will be triggered upon a barrier status change, for example, to send a broadcast, and create a broadcast receiver to receive the broadcast.
3. Define the label for the barrier and add the barrier.
4. Define the broadcast receiver to listen for the barrier event for further processing.
In this article we are explaining about Location Awareness, Headset Awareness, Ambient Light Awareness and Bluetooth Car Stereo Awareness.
Headset Awareness
For calling Headset Awareness capability we have to assign the given permissions in the manifest file.
Code:
<uses-permission android:name="android.permission.BLUETOOTH" />
Capture API
We can use the Capture API to detect whether the user currently has their headset connected or disconnected.
To get the headset status from the Capture API we need to call the getHeadsetStatus() method - this will return an instance of the HeadsetStatusResponse class that if successful, will contain information about the devices current headphone status.
Code:
private void getHeadsetStatus() {
// Use the getHeadsetStatus API to get headset connection status.
Awareness.getCaptureClient(this)
.getHeadsetStatus()
.addOnSuccessListener(new OnSuccessListener<HeadsetStatusResponse>() {
@Override
public void onSuccess(HeadsetStatusResponse headsetStatusResponse) {
HeadsetStatus headsetStatus = headsetStatusResponse.getHeadsetStatus();
int status = headsetStatus.getStatus();
String statusStr = "Headset is " +
(status == HeadsetStatus.CONNECTED ? "connected" : "disconnected");
headset_status_capture.setText(statusStr);
if(status==HeadsetStatus.CONNECTED) {
headset_status_capture.setTextColor(getColor(R.color.green));
headset_status_image.setImageDrawable(getDrawable(R.drawable.ic_headset_connected));
}else{
headset_status_capture.setTextColor(getColor(R.color.red));
headset_status_image.setImageDrawable(getDrawable(R.drawable.ic_volume_up));
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
headset_status_capture.setTextColor(getColor(R.color.red));
headset_status_capture.setText("Failed to get the headset capture.");
}
});
}
Barrier API
The given example illustrates how to develop a barrier triggered by the connecting condition. That is, the barrier will be triggered when the headset is connected or plugged in.
Code:
public class HeadsetBarrierActivity extends AppCompatActivity {
private TextView headset_status_barrier;
private ImageView headset_status_barrier_image;
PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.headset_barrier_activity);
headset_status_barrier=findViewById(R.id.headset_status_barrier);
headset_status_barrier_image=findViewById(R.id.headset_status_barrier_image);
// define PendingIntent that will be triggered upon a barrier status change.
final String BARRIER_RECEIVER_ACTION = getApplication().getPackageName() + "HEADSET_BARRIER_RECEIVER_ACTION";
Intent intent = new Intent(BARRIER_RECEIVER_ACTION);
pendingIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
HeadsetBarrierReceiver barrierReceiver = new HeadsetBarrierReceiver();
registerReceiver(barrierReceiver, new IntentFilter(BARRIER_RECEIVER_ACTION));
addbarrier();
}
private void addbarrier() {
//define the barrier
AwarenessBarrier headsetBarrier = HeadsetBarrier.keeping(HeadsetStatus.CONNECTED);
//define the label for the barrier and add the barrier
String headsetBarrierLabel = "headset keeping connected barrier";
//add the barrier
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(headsetBarrierLabel, headsetBarrier,pendingIntent).build();
Awareness.getBarrierClient(this).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getApplicationContext(), "add headset keeping barrier connected success", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(getApplicationContext(), "add headset keeping barrier connected failed", Toast.LENGTH_SHORT).show();
}
});
}
// define the broadcast receiver to listen for the barrier event.
private class HeadsetBarrierReceiver extends BroadcastReceiver {
private static final String TAG ="Headset Barrier" ;
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
switch(barrierStatus.getPresentStatus()) {
case BarrierStatus.TRUE:
headset_status_barrier.setTextColor(getColor(R.color.green));
headset_status_barrier.setText("Headset is connected");
headset_status_barrier_image.setImageDrawable(getDrawable(R.drawable.ic_headset_connected));
break;
case BarrierStatus.FALSE:
headset_status_barrier.setTextColor(getColor(R.color.red));
headset_status_barrier.setText("Headset is disconnected");
headset_status_barrier_image.setImageDrawable(getDrawable(R.drawable.ic_volume_up));
break;
case BarrierStatus.UNKNOWN:
headset_status_barrier.setTextColor(getColor(R.color.red));
headset_status_barrier.setText("unknown");
break;
}
}
}
}
Location Awareness
For calling Location Awareness capability we have to assign the given permissions in the manifest file.
Code:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Capture API
We can use the Capture API to Obtains the latitude and longitude of the current location.
To get the location from the Capture API we need to call the getLocation() method - this will return an instance of the LocationResponse class that if successful, will contain information about the location.
Code:
private void getLocation() {
Awareness.getCaptureClient(this).getLocation()
.addOnSuccessListener(new OnSuccessListener<LocationResponse>() {
@Override
public void onSuccess(LocationResponse locationResponse) {
Location location = locationResponse.getLocation();
Utils.setHomeLatitude(location.getLatitude());
Utils.setHomeLongitude(location.getLongitude());
location_details_capture.setText("Longitude:" + location.getLongitude()
+ ",Latitude:" + location.getLatitude());
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
location_details_capture.setText("Failed to get the location.");
}
});
}
Barrier API
Given an example in which a barrier is triggered by the enter condition. That is, the barrier will be triggered when a user enters his house.
Code:
public class LocationBarrierActivity extends AppCompatActivity {
private TextView location_details_barrier;
private ImageView location_image_barrier;
PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.location_barrier_activity);
location_details_barrier=findViewById(R.id.location_details_barrier);
location_image_barrier=findViewById(R.id.location_image_barrier);
// define PendingIntent that will be triggered upon a barrier status change.
final String BARRIER_RECEIVER_ACTION = getApplication().getPackageName() + "LOCATION_BARRIER_RECEIVER_ACTION";
Intent intent = new Intent(BARRIER_RECEIVER_ACTION);
pendingIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
LocationBarrierReceiver barrierReceiver = new LocationBarrierReceiver();
registerReceiver(barrierReceiver, new IntentFilter(BARRIER_RECEIVER_ACTION));
addbarrier(this);
}
private void addbarrier(Context context) {
//Home latitude and longitude
double latitude = Utils.getHomeLatitude();
double longitude = Utils.getHomeLongitude();
double radius = 200;
//define the barrier
AwarenessBarrier enterBarrier = LocationBarrier.enter(latitude, longitude, radius);
//define the label for the barrier and add the barrier
String locationBarrierLabel = "Home enter barrier";
//add the barrier
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(locationBarrierLabel, enterBarrier,pendingIntent).build();
Awareness.getBarrierClient(context).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getApplicationContext(), "add Home enter barrier barrier success", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(getApplicationContext(), "add Home enter barrier barrier failed", Toast.LENGTH_SHORT).show();
}
});
}
// define the broadcast receiver to listen for the barrier event
class LocationBarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
switch(barrierStatus.getPresentStatus()) {
case BarrierStatus.TRUE:
location_details_barrier.setText("You are at Home");
break;
case BarrierStatus.FALSE:
location_details_barrier.setText("You are away from home");
break;
case BarrierStatus.UNKNOWN:
location_details_barrier.setText("unknown");
break;
}
}
}
}
Ambient Light Awareness
Capture API
We can use the Capture API to obtain the illuminance of the environment where the device is located.
To get the light intensity from the Capture API we need to call the getLightIntensity () method - this will return us and instance of the AmbientLightResponse class that if successful, will contain information about the users light intensity.
Code:
private void getLightIntensity() {
Awareness.getCaptureClient(this).getLightIntensity()
.addOnSuccessListener(new OnSuccessListener<AmbientLightResponse>() {
@Override
public void onSuccess(AmbientLightResponse ambientLightResponse) {
AmbientLightStatus ambientLightStatus = ambientLightResponse.getAmbientLightStatus();
ambientLight_capture.setTextColor(getColor(R.color.green));
ambientLight_capture.setText("Light intensity is " + ambientLightStatus.getLightIntensity() + " lux");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
ambientLight_capture.setTextColor(getColor(R.color.red));
ambientLight_capture.setText("Failed to get the light intensity.");
}
});
}
Barrier API
We can use the Barrier API to set the ambient light barrier. For example, we can set the application to enable the auto flashlight function when the luminance is less than 20 lux. You can see the article "HMS Ambient Light Awareness for building an Auto Flash Light Application” for the reference.
Code:
public class AmbientLightBarrierActivity extends AppCompatActivity {
private TextView ambientLight_barrier;
private ImageView ambientLight_barrier_image;
PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ambient_light_barrier_activity);
ambientLight_barrier=findViewById(R.id.ambient_light_barrier);
ambientLight_barrier_image=findViewById(R.id.ambient_light_barrier_image);
// define PendingIntent that will be triggered upon a barrier status change.
final String BARRIER_RECEIVER_ACTION = getApplication().getPackageName() + "LIGHT_BARRIER_RECEIVER_ACTION";
Intent intent = new Intent(BARRIER_RECEIVER_ACTION);
pendingIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
LightBarrierReceiver barrierReceiver = new LightBarrierReceiver();
registerReceiver(barrierReceiver, new IntentFilter(BARRIER_RECEIVER_ACTION));
addbarrier(this);
}
private void addbarrier(Context context) {
//define lux here
final float luxValue = 60.0f;
//define the barrier
AwarenessBarrier lightAboveBarrier = AmbientLightBarrier.above(luxValue);
//define the label for the barrier and add the barrier
String lightBarrierLabel = "light above barrier";
//add the barrier
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(lightBarrierLabel, lightAboveBarrier,pendingIntent).build();
Awareness.getBarrierClient(context).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getApplicationContext(), "add light abov barrier success", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(getApplicationContext(), "add light above barrier failed", Toast.LENGTH_SHORT).show();
}
});
}
// define the broadcast receiver to listen for the barrier event.
class LightBarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
switch(barrierStatus.getPresentStatus()) {
case BarrierStatus.TRUE:
ambientLight_barrier.setTextColor(getColor(R.color.green));
ambientLight_barrier.setText("Room light is sufficient");
break;
case BarrierStatus.FALSE:
ambientLight_barrier.setTextColor(getColor(R.color.red));
ambientLight_barrier.setText("Room light is minimal");
break;
case BarrierStatus.UNKNOWN:
ambientLight_barrier.setTextColor(getColor(R.color.red));
ambientLight_barrier.setText("Unknown");
break;
}
}
}
}
Bluetooth Car Stereo Awareness
For calling Bluetooth Car Stereo Awareness capability we have to assign the given permissions in the manifest file.We have to assign the given permissions in the manifest file.
Code:
<uses-permission android:name="android.permission.BLUETOOTH" />
Capture API
We can use the Capture API to detect whether The Bluetooth car stereo is currently connected or disconnected.
To get the Bluetooth car stereo status from the Capture API we need to call the getBluetoothStatus(0) method - this will return an instance of the BluetoothStatusResponse class that if successful, will contain information about the The Bluetooth car stereo status.
Code:
private void getBluetoothStatus() {
int deviceType = 0; // Value 0 indicates a Bluetooth car stereo.
Awareness.getCaptureClient(this).getBluetoothStatus(deviceType)
.addOnSuccessListener(new OnSuccessListener<BluetoothStatusResponse>() {
@Override
public void onSuccess(BluetoothStatusResponse bluetoothStatusResponse) {
BluetoothStatus bluetoothStatus = bluetoothStatusResponse.getBluetoothStatus();
int status = bluetoothStatus.getStatus();
String statusStr = "The Bluetooth car stereo is " +
(status == BluetoothStatus.CONNECTED ? "connected" : "disconnected");
bluetooth_status_capture.setText(statusStr);
if(status== BluetoothStatus.CONNECTED) {
bluetooth_status_capture.setTextColor(getColor(R.color.green));
bluetooth_status_image.setImageDrawable(getDrawable(R.drawable.bluetooth_connected));
}else{
bluetooth_status_capture.setTextColor(getColor(R.color.red));
bluetooth_status_image.setImageDrawable(getDrawable(R.drawable.bluetooth_disconnected));
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
bluetooth_status_capture.setText("Failed to get Bluetooth status.");
}
});
}
Barrier API
The following example illustrates how to develop a barrier triggered by the connecting condition. That is, the barrier will be triggered when the Bluetooth car stereo is connected.
Code:
public class BluetoothBarrierActivity extends AppCompatActivity {
private TextView bluetooth_status_barrier;
private ImageView bluetooth_status_barrier_image;
PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bluetooth_barrier_activity);
bluetooth_status_barrier=findViewById(R.id.bluetooth_status_barrier);
bluetooth_status_barrier_image=findViewById(R.id.bluetooth_status_barrier_image);
// define PendingIntent that will be triggered upon a barrier status change.
final String BARRIER_RECEIVER_ACTION = getApplication().getPackageName() + "BLUETOOTH_BARRIER_RECEIVER_ACTION";
Intent intent = new Intent(BARRIER_RECEIVER_ACTION);
pendingIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
BluetoothBarrierReceiver barrierReceiver = new BluetoothBarrierReceiver();
registerReceiver(barrierReceiver, new IntentFilter(BARRIER_RECEIVER_ACTION));
addbarrier(this);
}
private void addbarrier(Context context) {
final int deviceType = 0; // Value 0 indicates a Bluetooth car stereo.
//define the barrier
AwarenessBarrier connectingBarrier = BluetoothBarrier.connecting(deviceType);
String bluetoothBarrierLabel = "bluetooth connecting barrier";
//add the barrier
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(bluetoothBarrierLabel, connectingBarrier,pendingIntent).build();
Awareness.getBarrierClient(context).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getApplicationContext(), "add bluetooth connecting barrier success", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(getApplicationContext(), "add bluetooth connecting barrier failed", Toast.LENGTH_SHORT).show();
}
});
}
// define the broadcast receiver to listen for the barrier event.
class BluetoothBarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
switch(barrierStatus.getPresentStatus()) {
case BarrierStatus.TRUE:
bluetooth_status_barrier.setTextColor(getColor(R.color.green));
bluetooth_status_barrier.setText("The Bluetooth car stereo is connected");
bluetooth_status_barrier_image.setImageDrawable(getDrawable(R.drawable.bluetooth_connected));
break;
case BarrierStatus.FALSE:
bluetooth_status_barrier.setTextColor(getColor(R.color.red));
bluetooth_status_barrier.setText("The Bluetooth car stereo is not connected");
bluetooth_status_barrier_image.setImageDrawable(getDrawable(R.drawable.bluetooth_disconnected));
break;
case BarrierStatus.UNKNOWN:
bluetooth_status_barrier.setText("Unknown");
break;
}
}
}
}
References:
https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/awareness-introduction

Make your own music player with Audio Kit: Part 3

More information like this, you can visit HUAWEI Developer Forum​
Original article link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201327669408150034&fid=0101187876626530001
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
After completing part two, which is "); background-size: 1px 1px; background-position: 0px calc(1em + 1px); font-size: 18px; text-decoration: underline;">here, not much left to implement, don’t you worry. Now. we will implement our playlist and a few additional UX-related features about it. Then we will implement advanced playback control buttons to further develop our versatility.
We will be using RecyclerView for the playlist and AudioKit play modes for the advanced playback controls. AudioKit makes it incredibly easy to implement those modes. Also, for viewing the playlist, I will use a bit “unconventional” ways and you can decide how unconventional it is.
If you remember our "); background-size: 1px 1px; background-position: 0px calc(1em + 1px); font-size: 18px; text-decoration: underline;">part 1, I said this:
Now, it is time to explain that code, because we will first implement the playlist feature, before implementing the advanced playback controls.
There I did this:
It first gets my custom adapter called PlaylistAdapter, set the layout manager of my RecyclerView (my playlist), sets the onClickListeners (to choose a song from) and finally calls the super method so that after initializing our managers in the task, let the AsyncTask do the rest that needs to be done.
If you have uncommented here previously, it is time to uncomment now and also let me share and explain the code of PlaylistAdapter, so you will not get ‘undefined’ errors. Create a new Java file for this, as you do for all adapters.
Code:
public class PlaylistAdapter extends RecyclerView.Adapter {
public interface OnItemClickListener {
void onItemClick (List myPlayList, int position);
}
private PlaylistAdapter.OnItemClickListener onItemClickListener;
List myPlayList;
public PlaylistAdapter(List myPlayList){
this.myPlayList = myPlayList;
}
public void setOnItemClickListener(PlaylistAdapter.OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
static class PlayListView extends RecyclerView.ViewHolder {
TextView songNameTextView;
TextView songArtistTextView;
TextView durationTextView;
ImageView moreOptionsImageView;
public PlayListView(View itemView) {
super(itemView);
songNameTextView = itemView.findViewById(R.id.songTitleTextView);
songArtistTextView = itemView.findViewById(R.id.songArtistTextView);
durationTextView = itemView.findViewById(R.id.durationTextView);
moreOptionsImageView = itemView.findViewById(R.id.moreOptionsImageView);
}
}
@NonNull
@Override
public PlayListView onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.playlist_detail_layout, parent, false);
return new PlayListView(layoutView);
}
@Override
public void onBindViewHolder(final PlayListView holder, final int position) {
HwAudioPlayItem currentItem = myPlayList.get(holder.getAdapterPosition());
holder.songNameTextView.setText(currentItem.getAudioTitle());
holder.songArtistTextView.setText(currentItem.getSinger());
long durationOfSong = currentItem.getDuration();
String totalDurationText = String.format(Locale.US, "d:d",
TimeUnit.MILLISECONDS.toMinutes(durationOfSong),
TimeUnit.MILLISECONDS.toSeconds(durationOfSong) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(durationOfSong))
);
holder.durationTextView.setText(totalDurationText);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(onItemClickListener != null) {
onItemClickListener.onItemClick(myPlayList, position);
}
}
});
}
@Override
public int getItemCount() {
return myPlayList.size();
}
}
This is one of the efficient and expandable (or let’s say: future-proof) ways of implementing onClickListener for a RecyclerView. There are other methods too and if you are knowledgable, you can implement your own way clicking RecyclerView items.
Since in part 1, I assumed some level of Android knowledge for this tutorial, I will not explain everything in the adapter, because it is not very very different than a normal custom adapter. I additionally implemented button interfaces. My constructor only has the playlist element, which I later process to view it in the playlist. I still convert my time 00:00 format because it is still a long value.
Also, do not forget to do this in your MainActivity:
And, because of that, you must implement onItemClick(…) method in the activity.
Code:
@Override
public void onItemClick(List myPlayList, int position) {
if (mHwAudioPlayerManager != null && mHwAudioQueueManager != null && mHwAudioQueueManager.getAllPlaylist() != null) {
/*
* 1. Obtains a playlist using the mHwAudioQueueManager.getAllPlaylist() method.
* 2. Compare myPlayList with mHwAudioQueueManager.
*/
if (mHwAudioQueueManager.getAllPlaylist() == myPlayList) {
//If the two playlists are the same, the user-specified song is played.
mHwAudioPlayerManager.play(position);
} else {
//If the two playlists are different, the mHwAudioPlayerManager playlist is updated.
//The music specified by the user is played.
mHwAudioPlayerManager.playList(playList, position, 0);
mHwAudioPlayerManager.setPlayMode(0);
mHwAudioQueueManager.setPlaylist(playList);
Log.w("Playlist", mHwAudioQueueManager.getAllPlaylist() + "");
}
}
}
/*
@Override
public void onItemClick(int position) {
if(mHwAudioPlayerManager != null){
mHwAudioPlayerManager.play(position);
}
}*/
And in MainActivity’s onItemClick(…) method, comments are put to further explain the code. If you do not like the verbose and think that this code looks complex, just comment the whole method and uncomment the below method (which is the same method with a simpler implementation). Be aware though, you should test it yourself to see whether it works for all cases.
Should you have any other questions regarding here (or anywhere else), please comment below, so I can address them.
Control Visibility
Now that our adapter is ready, we should control when/how the user can open it and when/how s/he can close it.
As I said before, my method may be a bit unconventional, so if you think you have a better idea you can implement it yourself. However, what I do is to add a constraint layout to the screen from the cover image to the bottom of the screen. Then, I control its visibility from GONE to VISIBLE, whenever the user clicks on the music button; and from VISIBLE to GONE whenever the user clicks on the music button and additionally, clicks on the back button.
Programmatically, I control the visibility in onCreate(…) method of the activity. And for the back button I override the onBackPressed(…) method. You can comment the onBackPressed(…) method completely and run the app, to see why I did it. This completely for user experience, in case the user wants to close the playlist with the back button click. I do it like this, it is simple enough to code them both:
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
//... your other codes
binding.containerLayout.setVisibility(View.GONE);
binding.playlistImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(binding.containerLayout.getVisibility() == View.GONE){
binding.containerLayout.setVisibility(View.VISIBLE);
}
else{
binding.containerLayout.setVisibility(View.GONE);
}
}
});
}
@Override
public void onBackPressed() {
if(binding.containerLayout.getVisibility() == View.VISIBLE){
binding.containerLayout.setVisibility(View.GONE);
}
else{
super.onBackPressed();
}
}
At first, I programmatically ensuring that the visibility of constraint layout is gone. You can also make it gone in the layout screen after you are done with the xml changes.
You should be done with the playlist now.
Advanced Playback Controls
Although they are called advanced controls, with the help of Huawei AudioKit, they are simpler to implement than they sound.
AudioKit offers 4 playback modes:
Code:
Playback modes:
0: sequential playback
1: shuffling songs
2: repeating a playlist
3: repeating a song
If you remember the code above, I set the playback mode as 0 in onItemClick(…) method, because we want the playback to be sequential if the user does not change anything explicitly.
Code:
protected void onCreate(Bundle savedInstanceState) {
//... your other codes
final Drawable shuffleDrawable = getDrawable(R.drawable.menu_shuffle_normal);
final Drawable orderDrawable = getDrawable(R.drawable.menu_order_normal);
final Drawable loopItself = getDrawable(R.drawable.menu_loop_one_normal);
final Drawable loopPlaylist = getDrawable(R.drawable.menu_loop_normal);
binding.shuffleButtonImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mHwAudioPlayerManager != null){
if(binding.shuffleButtonImageView.getDrawable().getConstantState().equals(shuffleDrawable.getConstantState())){
mHwAudioPlayerManager.setPlayMode(0);
binding.shuffleButtonImageView.setImageDrawable(getDrawable(R.drawable.menu_order_normal));
Toast.makeText(MainActivity.this,"Normal order",Toast.LENGTH_SHORT).show();
}
else if(binding.shuffleButtonImageView.getDrawable().getConstantState().equals(orderDrawable.getConstantState())){
mHwAudioPlayerManager.setPlayMode(1);
binding.shuffleButtonImageView.setImageDrawable(getDrawable(R.drawable.menu_shuffle_normal));
Toast.makeText(MainActivity.this,"Shuffle songs",Toast.LENGTH_SHORT).show();
}
}
}
});
binding.loopButtonImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mHwAudioPlayerManager != null){
if(binding.loopButtonImageView.getDrawable().getConstantState().equals(loopItself.getConstantState())){
mHwAudioPlayerManager.setPlayMode(2);
binding.loopButtonImageView.setImageDrawable(getDrawable(R.drawable.menu_loop_normal));
Toast.makeText(MainActivity.this,"Loop playlist",Toast.LENGTH_SHORT).show();
}
else if(binding.loopButtonImageView.getDrawable().getConstantState().equals(loopPlaylist.getConstantState())){
mHwAudioPlayerManager.setPlayMode(3);
binding.loopButtonImageView.setImageDrawable(getDrawable(R.drawable.menu_loop_one_normal));
Toast.makeText(MainActivity.this,"Loop the song",Toast.LENGTH_SHORT).show();
}
}
}
});
}
Let’s understand here. I get my drawables at first to compare them to each other. (You should know where to get them from by now, if you do not have them already.) After that, I implement onClicks of the buttons and change the playback modes as per the list I have given above. Also, I change the drawable to current playback drawable for better usability. At the end of every change, I notify the user about the change so that s/he knows what s/he just has changed into.
This feature also gives a good competitive edge, because with these buttons implemented, our music player looks more professional.
That is the end of my tutorial. I hope that you have benefitted from it. If you have any questions about any part of this tutorial, please comment in the related section. See you in the next tutorial!

Add View on Button click

public class MainActivity extends Activity {
MyView myView;
Button mButtonAdd;
@override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
myView.setBackgroundColor(Color.WHITE);
setContentView(R.layout.activity_main);
mButtonAdd = findViewById(R.id.buttonAdd);
mButtonAdd.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// do something here
setContentView(myView);
}
});
}
public class MyView extends View {
...
}
}
I have a button, when clicked it should show a view. However, the button seems to disappear 'under' the view shown on click of the button. How to maintain the button fixed, also able to add a view multiple times?

How come Im getting the default value the first time running the app?

Im following the steps laid out here for using the Settings Activity Template and despite some changes (e.g. now a root_preferences.xml file gets created instead of multiple xml files for different preference screens when selecting the Settings Activity template) I pretty much have nailed down the steps very similarly.
It says towards the end:
The first time you run the app, you should see "-1" displayed in the Toast because you haven't changed the setting yet.
Click to expand...
Click to collapse
However, instead of -1, Im seeing US as the toast message. Im thinking thats because its the default value, but they also set the default value as the US, yet the expectation according to the instructions is -1 the first time they run the app...how come?
Here is my code and the result Im getting first time running the app
SettingsActivity.java:
package com.example.droidcafe;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceFragmentCompat;
public class SettingsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public static class SettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
}
}
}
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent =
new Intent(MainActivity.this, OrderActivity.class);
intent.putExtra(EXTRA_MESSAGE, mOrderMessage);
startActivity(intent);
}
});
PreferenceManager.setDefaultValues(this,
R.xml.root_preferences, false);
SharedPreferences sharedPref = PreferenceManager
.getDefaultSharedPreferences(this);
String marketPref = sharedPref
.getString("market", "-1");
displayToast(marketPref);
}
root_preferences.xml
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/pref_header_account">
<ListPreference
app:defaultValue="US"
app:entries="@array/pref_market_titles"
app:entryValues="@array/pref_market_values"
app:key="market"
app:negativeButtonText="@null"
app:positiveButtonText="@null"
app:title="@string/pref_title_account" />
</PreferenceCategory>
</PreferenceScreen>
strings.xml:
<string name="pref_header_account">Account</string>
<!-- Sync Preferences -->
<string name="pref_title_account">Market</string>
<string-array name="pref_market_titles">
<item>United States</item>
<item>Canada</item>
<item>United Kingdom</item>
<item>India</item>
<item>Japan</item>
<item>Other</item>
</string-array>
<string-array name="pref_market_values">
<item>US</item>
<item>CA</item>
<item>UK</item>
<item>IN</item>
<item>JA0</item>
<item>-1</item>
</string-array>
first time running app:
Expectation: -1
I realize the default value is US, but their codelab default is also US, yet the codelab says it should display first time -1.

Categories

Resources