How to load an image in Android Studio using a Processing sketch - android-studio

I cannot load an image using a Processing sketch.
I am using Android Studio on Windows 10 with an android emulator. I have placed an image file called "car.png" in the following directory:
E:\Android\AndroidStudioProjects\car\app\src\main\res\drawable
I also placed it in the following directory using the Device File Explorer of Android Studio:
/data/user/0/com.example.ijusttrytoloadanimage/files/
When I double-click it from the Project tree or from the Device File Explorer, it shows the car image.
But when I run my project in Android Emulator I get the following error message:
W/System.err: java.io.FileNotFoundException: /data/user/0/com.example.ijusttrytoloadanimage/files/car.png (Permission denied)
This is my Sketch.java file:
package com.example.ijusttrytoloadanimage;
import processing.core.PApplet;
import processing.core.PImage;
public class Sketch extends PApplet {
public PImage car;
public void settings() {
fullScreen();
}
public void setup() {
imageMode(CENTER);
car = loadImage("car.png");
}
public void draw() {
background(0);
translate((float) width/2, (float) height/2);
if (car != null) {
image(car, 0, 0);
} else {
print("nothing shows up!");
}
}
The message I get when running the Sketch.java is "nothing shows up!" meaning that the PImage variable car is still empty.
Why I get this permission denied message although I use the internal storage which by default has its access granted? What should I do to show my image file to the emulator's screen?
This is my MainActivity.java file:
package com.example.ijusttrytoloadanimage;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import processing.android.PFragment;
import processing.android.CompatUtils;
import processing.core.PApplet;
public class MainActivity extends AppCompatActivity {
private PApplet sketch;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CompatUtils.getUniqueViewId());
setContentView(frame, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
sketch = new Sketch();
PFragment fragment = new PFragment(sketch);
fragment.setView(frame, this);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (sketch != null) {
sketch.onRequestPermissionsResult(
requestCode, permissions, grantResults);
}
}
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (sketch != null) {
sketch.onNewIntent(intent);
}
}
}
This is my AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ijusttrytoloadanimage">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.ijusttrytoloadanimage"
>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

I finally found the answer. If anyone else has the same problem, just do the following:
In Project View right-click on app and select New -> Directory. Type the name "assets" in the new window and select src/main/assets from below.
Copy your image file to the new directory app/src/main/assets.
Load your image in your Sketch.java file with the command loadImage(your_image.png);
It works!

Related

Action_Call permission not granted in Android Studio

I am trying to make an app which can directly call if the number is entered but the permission is not granted and hence no call is made...
I have requested permission in AndriodManifest.xml
Everytime I enter a number, "Hello" pops up which is written if Granted is Not Granted.
My code:
MainActivity.java
package com.example.block9;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void redirectmessage(View v) {
String number = (((EditText) findViewById(R.id.mobnumber)).getText()).toString();
String message = (((EditText) findViewById(R.id.textmessage)).getText()).toString();
Uri num = Uri.parse("smsto:" + number);
Intent smsIntent = new Intent(Intent.ACTION_SENDTO, num);
smsIntent.putExtra("sms_body", message);
startActivity(smsIntent);
}
public void redirectcall(View v) {
String number = (((EditText) findViewById(R.id.mobnumber)).getText()).toString();
Toast t = null;
//t.makeText(getApplicationContext(),number,Toast.LENGTH_SHORT).show();
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + number));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
t.makeText(getApplicationContext(),"Hello",Toast.LENGTH_SHORT).show();
return;
}
startActivity(callIntent);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.block9">
<uses-permission android:name="android.permission.CALL_PHONE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Any Help would be Appreciated!!`enter code here.
If your Target Device API is <22 then you don't need to ask for permission as the permission will automatically provide But as a Developer you have to ready for every possibility. in case if target device API is >=23 then you have to manually request the permission. For more information on this Read this
public void redirectcall(View v) {
String number = (((EditText) findViewById(R.id.mobnumber)).getText()).toString();
Toast t = null;
//t.makeText(getApplicationContext(),number,Toast.LENGTH_SHORT).show();
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + number));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
t.makeText(getApplicationContext(),"Hello",Toast.LENGTH_SHORT).show();
grantPermission();
return;
}
startActivity(callIntent);
}
private void grantPermission() {
// show your dialog box to ask for permission
new AlertDialog.Builder(this)
.setTitle("Call Permission Required")
.setMessage("This App needs Call permission, to function properly")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT)
.show();
}
})
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//here permission will be given
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 3); // 3 is requestCode and can be any number
}
})
.create()
.show();
}
After Making a Request Now, we will call #Override method onRequestPermissionsResult() to handle the scenario of Rejected or accepted Request
*#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 3: //remember that 3 is the same number which we specified while requesting
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// Call-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE)
== PackageManager.PERMISSION_GRANTED) {
redirectcall();
}
}else{
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
}
}
}*
Full MainActivity.java code is here: https://gist.github.com/Shoaibpython/eda5394ee4bc441396d68d5ef603cd3
Please consider replying here if you saw any error.

Android Studio Code Dont Work On Android Version 9.0

Please My Android App works well in any android app version but dont work on android 9.0 ??
there is no errors display when run the code from android studio on emulator ..
this is my login_activity.java
package com.steam.carwash.activities;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.icanstudioz.sclient.R;
import com.steam.carwash.Server.Server;
import com.steam.carwash.custom.MyApplication;
import com.steam.carwash.fragment.ForgotPassword;
import com.steam.carwash.model.ResObj;
import com.steam.carwash.model.User;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.Callback;
import com.lzy.okgo.model.HttpParams;
import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.base.Request;
import com.norbsoft.typefacehelper.TypefaceHelper;
import com.steam.carwash.permissionhelper.ActivityManagePermission;
import org.json.JSONObject;
import okhttp3.ResponseBody;
public class LoginActivity extends ActivityManagePermission {
EditText email, password;
Button login;
TextView register, forgot;
private ProgressDialog mProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
bindViews();
}
private void bindViews() {
mProgress = new ProgressDialog(this);
mProgress.setTitle("Processing...");
mProgress.setMessage("Please wait...");
mProgress.setCancelable(false);
mProgress.setIndeterminate(true);
email = findViewById(R.id.input_email);
password = findViewById(R.id.input_password);
login = findViewById(R.id.btn_login);
register = findViewById(R.id.txt_register);
forgot = findViewById(R.id.txt_forgot);
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
finish();
}
});
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (validate()) {
final String eml = email.getText().toString().trim();
final String pwd = password.getText().toString().trim();
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
Toast.makeText(LoginActivity.this, "Error", Toast.LENGTH_SHORT).show();
loginUser(eml, pwd,instanceIdResult.getToken());
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
loginUser(eml, pwd,"");
}
});
}
}
});
forgot.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this, ForgotPassword.class));
}
});
TypefaceHelper.typeface(email, MyApplication.getLight());
TypefaceHelper.typeface(password, MyApplication.getLight());
TypefaceHelper.typeface(register, MyApplication.getRegular());
TypefaceHelper.typeface(forgot, MyApplication.getRegular());
TypefaceHelper.typeface(login, MyApplication.getRegular());
}
private Boolean validate() {
String eml = email.getText().toString().trim();
String pwd = password.getText().toString().trim();
if (!Patterns.EMAIL_ADDRESS.matcher(eml).matches()) {
email.setError(getString(R.string.email_is_invalid));
} else if (pwd.isEmpty()) {
password.setError(getString(R.string.password_is_required));
} else {
//Toast.makeText(LoginActivity.this, "Is Valid", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
private void loginUser(String email, String password, String token) {
Toast.makeText(LoginActivity.this, "okiii", Toast.LENGTH_SHORT).show();
HttpParams params = new HttpParams();
params.put("type", "simple");
params.put("utype", "0");
params.put("email", email);
params.put("password", password);
params.put("fcm_token", token);
OkGo.<ResObj<User>>post(Server.BASE_URL + "user/login").params(params).execute(new Callback<ResObj<User>>() {
#Override
public void onStart(Request<ResObj<User>, ? extends Request> request) {
//Toast.makeText(LoginActivity.this, "ok", Toast.LENGTH_SHORT).show();
}
#Override
public void onSuccess(Response<ResObj<User>> response) {
Toast.makeText(LoginActivity.this, "Login On Success", Toast.LENGTH_SHORT).show();
if (response.body() != null) {
Toast.makeText(LoginActivity.this, "Good Job", Toast.LENGTH_SHORT).show();
ResObj<User> userResObj = response.body();
User user = userResObj.getData();
HttpParams params1=new HttpParams();
params1.put("access_token",user.getAccess_token());
params1.put("user_id",user.getId());
OkGo.getInstance().addCommonParams(params1);
MyApplication.getInstance().setUser(user);
MyApplication.getInstance().createLoginSession(user.getName(), user.getEmail(), user.getId(), user.getFcm_token(),user.getAccess_token());
startActivity(new Intent(LoginActivity.this, HomeActivity.class));
Toast.makeText(LoginActivity.this, "Good b", Toast.LENGTH_SHORT).show();
finish();
}
else
Toast.makeText(LoginActivity.this, "Error 2", Toast.LENGTH_SHORT).show();
}
#Override
public void onCacheSuccess(Response<ResObj<User>> response) {
}
#Override
public void onError(Response<ResObj<User>> response) {
}
#Override
public void onFinish() {
}
#Override
public void uploadProgress(Progress progress) {
}
#Override
public void downloadProgress(Progress progress) {
}
#Override
public ResObj<User> convertResponse(okhttp3.Response response) throws Throwable {
try {
ResponseBody responseBody = response.body();
String s = responseBody.string();
JSONObject jsonObject = new JSONObject(s);
Toast.makeText(LoginActivity.this, s, Toast.LENGTH_SHORT).show();
if (jsonObject.getString("status").equalsIgnoreCase("success")) {
return new Gson().fromJson(s, new TypeToken<ResObj<User>>() {
}.getType());
} else {
MyApplication.getInstance().showToast(LoginActivity.this, jsonObject.getString("data"));
}
} catch (Exception e) {
//Log.e("catch", e.toString());
Toast.makeText(LoginActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
return null;
}
});
}
}
and this is my androidmainfest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.icanstudioz.sclient">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:networkSecurityConfig="#xml/network_security_config"
android:debuggable="true"
android:name="com.steam.carwash.custom.MyApplication"
android:allowBackup="true"
android:icon="#drawable/splash"
android:label="#string/app_name"
android:roundIcon="#drawable/boy"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="HardcodedDebugMode">
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<activity android:name="com.steam.carwash.activities.SplashScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.steam.carwash.fragment.ForgotPassword"/>
<activity android:name="com.steam.carwash.permissionhelper.ActivityManagePermission"/>
<activity
android:name="com.steam.carwash.activities.HomeActivity"
android:fitsSystemWindows="true"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
<activity android:name="com.steam.carwash.activities.LoginActivity" />
<activity android:name="com.steam.carwash.activities.PaymentActivity"/>
<activity
android:name="com.steam.carwash.activities.RegisterActivity"
android:windowSoftInputMode="adjustPan" />
<activity android:name="com.steam.carwash.activities.fullImage" />
<service android:name="com.steam.carwash.Server.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/c_id" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher_foreground" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
notification message. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorPrimaryDark" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBX8-V0iihmTnrgwYlyI5GdP0GKjwfTTd8" />
</application>
when run this on android version 8.0 or below its work well ... but the problem is on version 9 or above ??
just put the below line in manifest under application tag and try
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
if doesnt work try adding below line
android:usesCleartextTraffic="true under application tag and even if it doesnt work try adding android:networkSecurityConfig="#xml/network_security_config in application tag where network_security_config.xml is<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
Create xml under res directory and then network_security_config.xml in xml folder

Broadcast receiver to read incoming sms

My app to read incoming sms using broadcast receiver is working fine in many mobiles but not working in samsung j5 mobile. Can you give me proper solution for that problem.
My MainActivity.java is
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyReceiver.bindListener(new SmsListener.OTPListener() {
#Override
public void messageReceived(String messageText, String messageSender) {
Toast.makeText(MainActivity.this,"message is "+messageText+ " and sender is "+messageSender ,Toast.LENGTH_SHORT).show();
}
});
}
}
MyReceiver.java
public class MyReceiver extends BroadcastReceiver {
private static SmsListener.OTPListener mListener;
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) {
Bundle data = intent.getExtras();
Object[] pdus = new Object[0];
if(data != null)
{
pdus = (Object[]) data.get("pdus");
}
if(pdus != null)
{
for(Object pdu : pdus ){
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[])pdu);
String sender = smsMessage.getDisplayOriginatingAddress();
String messageBody = smsMessage.getMessageBody();
if (mListener!=null)
{
mListener.messageReceived(messageBody, sender);
break;
}
}
}
}
public static void bindListener(SmsListener.OTPListener listener) {
mListener = listener;
}
public static void unbindListener() {
mListener = null;
}
}
SmsListener.java
public interface SmsListener {
interface OTPListener{
void messageReceived(String messageText,String messageSender);
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.aaa.aaa">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.BROADCAST_SMS"
tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="#drawable/b"
android:label="#string/app_name"
android:roundIcon="#drawable/b"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:priority="2147483647"
android:name=".MyReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS"
>
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
This is my application code. I want to toast the message and sender when a new message is arrived (even app is killed or destroyed), but in samsung j5 mobile, nothing happened.
You are probably running into a permission issue. The Samsung J5 is an older Samsung model, so I assume your other "mobiles" are also older phones running older android releases. Which leads me to think that you maybe running into a permission issue with the J5 as it would probably be running a newer android release. Here is how you can get permission to read SMS on newer android releases!

Unity3d Application crashes when use Android plugin

I am following this tutorial to make a step counter and it works well as an android project but when I make the android project a library and want to use it in unity3d, it is crashing and giving me an error class not found: exception
My unity code is as follows:
void Start ()
{
#if UNITY_ANDROID
AndroidJNI.AttachCurrentThread();
androidClass = new AndroidJavaClass("com.test.testapp.MainActivity");
#endif
}
#if UNITY_ANDROID
public void checkMyIntOnJava(string message){
if (message == "READY") {
int myInt = androidClass.CallStatic<int>("getMyInt");
guiText.text = "My Int: " + myInt;
}
}
and my android code is as follows:
public class MainActivity extends UnityPlayerActivity
implements OnDataPointListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener
{
public static void callbackToUnityMethod(int num, String gameObject,String methodName){
_myInt = num;
Log.e("GoogleFit", "in callbackToUnityMethod");
UnityPlayer.UnitySendMessage(gameObject, methodName, "READY");
}
}
After making an android jar, I keep it in the plugin folder in unity3d.
Did I miss anything?
My Android Manifest file is as following:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.testapp" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<application android:label="#string/app_name">
<activity android:name="com.xxx.testapp.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.xxx.testapp.UnityPlayerActivity"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"
android:label="#string/app_name" android:launchMode="singleTask" android:theme="#android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
</application>
</manifest>
Here's the two things I would try.
First change the following line in you AndroidManifest.xml so that the package scoping matches on the android:name property.
<activity android:name="com.xxx.testapp.MainActivity"
android:label="#string/app_name">
to
<activity android:name="com.test.testapp.MainActivity"
android:label="#string/app_name">
The other potential problem is that your class isn't being compiled because it is missing concrete implementations of the abstract methods in the parents classes and interfaces. To fix that add these implementations to MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onDataPoint(DataPoint dataPoint) {
}

Android refreshed UI is overlapping instead of replacing old image when onLayout is called

I've got a fairly simple app I wrote to sharpen my JNI and multi-threading skills which takes either a string of ascii characters to convert to a binary string or a binary character string to convert to an ascii character string. The math behind each conversion is processed via a native lib, and each call to the native code runs on its own thread using AsyncTask so as not to disrupt the UI. The trouble is that whenever onLayout is called when the UI widgets need to change size or position, the new image is placed over top of the still visible old image rather than replacing it. I've tried removing likely culprits (the JNI module, the AsyncTask module) but even when its functionality is stripped and only the UI remains I see the same result of new UI views overlapping instead of replacing older views. As you can see from my code below, I've also variably tried the old setContentView(...) approach to UI hierarchy modeling in addition to the more flexible custom addView model I have active now, but the results were still the same. NOTE: This only happens on device (Nexus 7 running latest 4.2.1 and Nexus S running 4.0.2); in the emulator everything works fine. This would seem to implicate GLES invocations, but I don't make any of my own in this app and obviously this isn't happening to every app on device so it doesn't seem like an OS issue...
Activity Class:
package cresco.ai.asciitobinstring.core;
import android.app.Activity;
import android.os.Bundle;
public class AsciiToBinActivity_Minimalist extends Activity{
private AsciiToBin_Main hMain;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
hMain = new AsciiToBin_Main(this);
hMain.init();
}
#Override
protected void onResume(){
super.onResume();
}
#Override
protected void onPause(){
super.onPause();
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onRestart(){
super.onRestart();
}
#Override
protected void onDestroy(){
super.onDestroy();
}
}
Main manager class:
package cresco.ai.asciitobinstring.core;
import cresco.ai.asciitobinstring.gui.ConversionViewController;
import cresco.ai.asciitobinstring.gui.DefineLayoutParams;
import cresco.ai.asciitobinstring.gui.TutorialViewController;
import cresco.ai.asciitobinstring.math.StringConverter;
import android.app.Activity;
import android.content.res.AssetManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.ViewFlipper;
public class AsciiToBin_Main {
private Activity hAct;
private View mvMainView;
private ViewFlipper mvRootViewFlipper;
private ConversionViewController mvConversionViewController;
private TutorialViewController mvTutorialViewController;
private RelativeLayout mvRootRL;
private AssetManager mvAssetManager;
private LayoutInflater mvInflater;
private StringConverter mvConverter;
public AsciiToBin_Main(Activity act){
hAct = act;
mvConverter = new StringConverter(this);
mvRootRL = new RelativeLayout(hAct);
hAct.addContentView(mvRootRL,
DefineLayoutParams.getParams(DefineLayoutParams.getMM()));
//hAct.setContentView(mvRootRL);
///hAct.setContentView(R.layout.conversion_layout);
}
public void init(){
//Add the viewgroup subclass viewflipper to the rootRL
mvRootViewFlipper = new ViewFlipper(hAct);
mvRootRL.addView(mvRootViewFlipper);
//Instantiate our conversion view controller
mvConversionViewController = new ConversionViewController(this);
mvTutorialViewController = new TutorialViewController(this);
//Fire up the conversion view
mvConversionViewController.initGUI();
mvConversionViewController.initSpinnerElements();
//Fire up the tutorial view
mvTutorialViewController.initGUI();
}
public RelativeLayout getRootRL(){
return mvRootRL;
}
public ViewFlipper getRootViewFlipper(){
return mvRootViewFlipper;
}
public View getMainView(){
return mvMainView;
}
public Activity getAct(){
return hAct;
}
public void setMainView(View v){
mvMainView = v;
}
public void setActivity(Activity a){
hAct = a;
}
public StringConverter getConverter(){
return mvConverter;
}
public void setConverter(StringConverter sc){
mvConverter = sc;
}
}
Conversion View Controller:
package cresco.ai.asciitobinstring.gui;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
import cresco.ai.asciitobinstring.core.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
public class ConversionViewController extends View implements OnClickListener,
OnItemSelectedListener{
private AsciiToBin_Main hMain;
private LayoutInflater mvInflater;
private View mvConversionView;
private Button mvConvertB;
private Button mvToTutorialB;
private Spinner mvConversionTypeSP;
private EditText mvAsciiStringET;
private EditText mvBinStringET;
private ArrayAdapter<CharSequence> mvSpinnerAdapter;
public ConversionViewController(AsciiToBin_Main main) {
super(main.getAct());
hMain = main;
}
public void initGUI(){
mvInflater = (LayoutInflater)
hMain.getAct().getSystemService(hMain.getAct().LAYOUT_INFLATER_SERVICE);
mvConversionView = mvInflater.inflate(R.layout.conversion_layout,
hMain.getRootViewFlipper(),false);
hMain.getRootViewFlipper().addView(mvConversionView);
//hMain.getRootRL().addView(mvConversionView);
mvConvertB = (Button)hMain.getAct().findViewById(R.id.convertB);
mvToTutorialB =
(Button)hMain.getAct().findViewById(R.id.conversion_To_Tutorial_B);
mvAsciiStringET =
(EditText)hMain.getAct().findViewById(R.id.asciiStringET);
mvBinStringET = (EditText)hMain.getAct().findViewById(R.id.binStringET);
mvConversionTypeSP =
(Spinner)hMain.getAct().findViewById(R.id.conversionTypeSP);
mvConvertB.setOnClickListener(this);
mvToTutorialB.setOnClickListener(this);
mvConversionTypeSP.setOnItemSelectedListener(this);
}
public void initSpinnerElements(){
mvSpinnerAdapter = ArrayAdapter.createFromResource(hMain.getAct(),
R.array.conversion_choices_array, android.R.layout.simple_spinner_item);
mvSpinnerAdapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
mvConversionTypeSP.setAdapter(mvSpinnerAdapter);
mvConversionTypeSP.setSelection(0);
//Now that that the UI is ready, display it
////hMain.getRootViewFlipper().showNext();
}
#Override
protected void onDraw(Canvas c){
super.onDraw(c);
}
#Override
public void onClick(View v) {
if(v==mvConvertB){
Log.d("me", "button pressed! Conversion type selected currently is
"+mvSpinnerAdapter.getItem(mvConversionTypeSP.getSelectedItemPosition()));
if(mvConversionTypeSP.getSelectedItemPosition() == 0){
//This is the convert ascii to binary string choice
//Calls the native method calculateBinFromAsciiStringJNI
//Not a terribly heavy process, but since it is disparate
//from
//the UI we should probably grant it its own thread...
//Uncomment when UI overlay bug is solved
new
NativeStringConversionTask(0).execute(mvAsciiStringET.getText().toString());
//mvBinStringET.setText(hMain.getConverter().
//calculateBinFromAsciiStringJNI(mvAsciiStringET
//.getText().toString())); //all on the UI thread, not good
}
else if(mvConversionTypeSP.getSelectedItemPosition() == 1){
//This is the convert binary to ascii string choice
//Uncomment when UI overlay bug is solved
new
NativeStringConversionTask(1).execute(mvBinStringET.getText().toString());
//mvAsciiStringET.setText(hMain.getConverter().
//calculateAsciiFromBinStringJNI(mvBinStringET
//.getText().toString())); //all on the UI thread. Not good
}
}
else if(v==mvToTutorialB){
//hMain.getRootViewFlipper().setDisplayedChild(1);
hMain.getRootViewFlipper().showNext();
//hMain.getAct().setContentView(R.layout.tutorial_layout);
}
}
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Log.d("me", "itemselectedlistener received a callback! the position
selected is "+arg2);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
Log.d("me", "itemselectedlistener received a no items slected callaback");
}
//Uncomment once the UI overlay issue is solved
private class NativeStringConversionTask extends AsyncTask<String,Integer,String>{
private int taskID = 0;
public NativeStringConversionTask(int id){
taskID = id;
}
#Override
protected void onPreExecute(){
Log.d("me","in the preExecute of the nativeStringConversion Async
task");
}
#Override
protected String doInBackground(String... s) {
//NB: if we wanted onProgressUpdate to be called with something we
//would
//invoke publishProgress(something) in this function
Log.d("me", "bg task started with taskID "+taskID);
if(taskID == 0){
publishProgress(taskID);
return
hMain.getConverter().calculateBinFromAsciiStringJNI(s[0].toString());
}
else if (taskID == 1){
publishProgress(taskID);
return
hMain.getConverter().calculateAsciiFromBinStringJNI(s[0].toString());
}
else{
publishProgress(taskID);
return "This shouldn't appear. if it does... may the
gods below help us all";
}
}
#Override
protected void onProgressUpdate(Integer... progress){
Log.d("me", "progressUpdate called!");
}
#Override
protected void onPostExecute(String result){
Log.d("me", "calling postExecute...");
if(taskID == 0){
mvBinStringET.setText((String)result);
}
else if (taskID == 1){
mvAsciiStringET.setText((String)result);
}
else{
mvBinStringET.setText("This shouldn't appear. if it
does... may the gods below help us all");
mvAsciiStringET.setText("This shouldn't appear. if it
does... may the gods below help us all");
}
//mvBinStringET.setText(s);
}
}
}
Tutorial View Controller:
package cresco.ai.asciitobinstring.gui;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
import cresco.ai.asciitobinstring.core.R;
public class TutorialViewController extends View implements OnClickListener{
private AsciiToBin_Main hMain;
private LayoutInflater mvInflater;
private View mvTutorialView;
private Button mvToConversionB;
public TutorialViewController(AsciiToBin_Main main){
super(main.getAct());
hMain = main;
}
public void initGUI(){
mvInflater = (LayoutInflater)
hMain.getAct().getSystemService(hMain.getAct().LAYOUT_INFLATER_SERVICE);
mvTutorialView = mvInflater.inflate(R.layout.tutorial_layout,
hMain.getRootViewFlipper(),false);
hMain.getRootViewFlipper().addView(mvTutorialView);
mvToConversionB =
(Button)hMain.getAct().findViewById(R.id.tutorial_Conversion_B);
mvToConversionB.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==mvToConversionB){
//hMain.getRootViewFlipper().setDisplayedChild(0);
hMain.getRootViewFlipper().showNext();
//hMain.getAct().setContentView(R.layout.conversion_layout);
}
}
}
StringConverter:
package cresco.ai.asciitobinstring.math;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
public class StringConverter {
private AsciiToBin_Main hMain;
public StringConverter(AsciiToBin_Main main){
hMain = main;
}
//Uncomment once the UI overlay issue is solved
public native String calculateBinFromAsciiStringJNI(String s);
public native String calculateAsciiFromBinStringJNI(String s);
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("ascii2bin");
}
}
conversion_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/asciiStringET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/conversionTypeSP"
android:layout_centerHorizontal="true"
android:layout_marginTop="71dp"
android:hint="Your ASCII string goes here"
android:text="" />
<EditText
android:id="#+id/binStringET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/asciiStringET"
android:layout_below="#+id/asciiStringET"
android:layout_marginTop="61dp"
android:hint="Your binary string goes here"
android:text="" />
<Button
android:id="#+id/convertB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="#+id/binStringET"
android:text="Convert Strings!" />
<Button
android:id="#+id/conversion_To_Tutorial_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="#+id/convertB"
android:text="Read the tutorial on binary numbers" />
<Spinner
android:id="#+id/conversionTypeSP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:layout_marginTop="57dp" />
</RelativeLayout>
tutorial_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/tutorial_Conversion_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="204dp"
android:text="Return to Conversion" />
</RelativeLayout>
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cresco.ai.asciitobinstring.core"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="cresco.ai.asciitobinstring.core.AsciiToBinActivity_Minimalist"
android:label="#string/app_name"
android:theme="#style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The results I'm seeing are as follows:
Now what's curious is that if I put the app in the background and then re-open it (so onPause and onResume are called) the UI that loads is refreshed properly, with old view artifacts removed. Of course attempting a new string conversion that resizes the edittext widgets creates the overlap again.
Does anyone know what might be behind this? I am targeting sdk revision 17, standard libs with a minSDK of 8. When I first saw this I thought it was a weird side-effect of the new-ish holo UI scheme, so I rolled back the styles.xml to a 2.3 compliant UI scheme but I didn't see any improvement. could be that messed something up separately...
this isn't really a good answer per se because it certainly doesn't explain what happened in the first place, but I found that creating a new project from scratch fixed the odd errors I was seeing; therefore the problem was most likely caused by my mucking about with the UI styles... wish I had a more technical explanation than that, but at present I don't. Anyway, if anyone else runs into this, re-creating your project seems to clear the problem. If anyone has more explanatory details they'd like to add, please feel free!

Resources