I am trying to make tests for ActivityStarter library, which is using annotation processing, but I get strange error:
An expected source declared one or more top-level types that were not present.
Expected top-level types: <[MainActivityStarter]>
Declared by expected file:
<com/example/activitystarter/MainActivityStarter.java>
The top-level types that were present are as follows:
- [ainActivityStarter] in </SOURCE_OUTPUT/ainActivityStarter.java>
When I started:
import com.google.testing.compile.JavaFileObjects
import org.junit.Test
import javax.tools.JavaFileObject
import activitystarter.compiler.ActivityStarterProcessor
import com.google.common.truth.Truth.assertAbout
import com.google.testing.compile.JavaSourceSubjectFactory
import org.junit.Assert.*
import com.google.testing.compile.JavaSourceSubjectFactory.javaSource
import com.google.testing.compile.JavaSourcesSubject
import com.google.testing.compile.JavaSourcesSubject.SingleSourceAdapter
import com.google.testing.compile.JavaSourcesSubjectFactory.javaSources
class ActivityStarterTest() {
#Test
fun simpleGenerationTest() {
val beforeProcess = "com.example.activitystarter.MainActivity" to """
import android.app.Activity;
import activitystarter.MakeActivityStarter;
#MakeActivityStarter
public class MainActivity extends Activity {}
"""
val afterProcess = "com.example.activitystarter.MainActivityStarter" to """
import android.content.Context;
import android.content.Intent;
import android.support.annotation.UiThread;
public class MainActivityStarter {
#UiThread
public static void fill(MainActivity activity) {
}
#UiThread
public static void start(Context context) {
Intent intent = new Intent(context, MainActivity.class);
context.startActivity(intent);
}
#UiThread
public static void startWithFlags(Context context, int flags) {
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(flags);
context.startActivity(intent);
}
#UiThread
public static Intent getIntent(Context context) {
Intent intent = new Intent(context, MainActivity.class);
return intent;
}
}
"""
processingComparator(beforeProcess, afterProcess)
}
fun processingComparator(beforeProcess: Pair<String, String>, afterProcess: Pair<String, String>) {
val source = JavaFileObjects.forSourceString(beforeProcess.first, beforeProcess.second)
val bindingSource = JavaFileObjects.forSourceString(afterProcess.first, afterProcess.second)
assertAbout<SingleSourceAdapter, JavaFileObject, JavaSourceSubjectFactory>(javaSource())
.that(source)
.processedWith(ActivityStarterProcessor())
.compilesWithoutWarnings()
.and()
.generatesSources(bindingSource)
}
}
Both before and after process code was taken from real code before and after process, so it should be ok. Also, in lib there is no way of cutting this first letter:
JavaFile brewJava() {
return JavaFile.builder(bindingClassName.packageName(), getActivityStarterSpec())
.addFileComment("Generated code from ActivityStarter. Do not modify!")
.build();
}
private TypeSpec getActivityStarterSpec() {
TypeSpec.Builder result = TypeSpec
.classBuilder(bindingClassName.simpleName())
.addModifiers(PUBLIC);
and:
bindingClassName = ClassName.get(packageName, className + "Starter");
Any idea how do deal with it?
Related
The documentation for "How do I handle incoming intents from external applications in Flutter?" at https://flutter.dev/docs/get-started/flutter-for/android-devs#how-do-i-handle-incoming-intents-from-external-applications-in-flutter has code for the MainActivity written in Java. Yet there is no Kotlin equivalent but my Flutter project builds Kotlin files. Hence, all I need is the Kotlin equivalent for the following Java code (or at least as close to it as possible, I'm sure I can figure out the rest):
package com.example.shared;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private String sharedText;
private static final String CHANNEL = "app.channel.shared.data";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
}
}
}
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
);
}
void handleSendText(Intent intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
}
}
(I could learn Java but zero of my work involve Java until now, so it doesn't seem efficient to learn Java just to translate this one file.)
Thanks to #che10's hint to use Android Studio's Jave to Kotlin converter (https://developer.android.com/kotlin/add-kotlin#convert), I was able to convert to a baseline that was almost compilable. The compile errors were enough clues to tell me what were the remaining touchups I had to do. The result is below:
package com.example.shared
import android.content.Intent
import android.os.Bundle
import androidx.annotation.NonNull
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
private var sharedText: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent: Intent = getIntent()
val action: String? = intent.getAction()
val type: String? = intent.getType()
if (Intent.ACTION_SEND == action && type != null) {
if ("text/plain" == type) {
handleSendText(intent) // Handle text being sent
}
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText)
sharedText = null
}
}
}
fun handleSendText(intent: Intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
companion object {
private const val CHANNEL = "app.channel.shared.data"
}
}
I am getting a failure when trying to open an android activity while the application is closed. See in the code below that, when I receive a notification of data from firebase, while the app is in the background, I should open an activity using MethodChannel to access java, but I get this error:
No implementation found for method openActivity on channel com.example.service/start
Application.java
package com.example.mobile;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
#Override
public void onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
#Override
public void registerWith(PluginRegistry registry) {
FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
}
AndroidManifest.xml
<application
android:name="com.example.mobile.Application"
android:label="mobile"
android:icon="#mipmap/ic_launcher">
MainActivity.java
package com.example.mobile;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.service/start";
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if(call.method.equals("openActivity")){
openActivity();
result.success("open activity");
}
}
);
}
void openActivity(){
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
}
}
main.dart
_firebaseMessaging.configure(
onMessage: (message) async {
//
},
onLaunch: (message) {
//
},
onResume: (message) {
//
},
onBackgroundMessage: myBackgroundMessageHandler,
);
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
MethodChannel channel = new MethodChannel("com.example.service/start");
if (message.containsKey('data')) {
final dynamic data = message['data'];
var open = await channel.invokeMethod("openActivity");
}
}
Where am I going wrong, and how can I make it work?
In your AndroidManifest.xml file the android:name must be android:name=".Application", And make sure that MainActivity.java and Application.java are in same folder
I'm trying to follow Facebook's docs for Sharing a Sticker Asset on Android without any luck. Basically when executed the app flickers and then crash.
Could someone look at this code and point out why the app crashes after calling activity.startActivityForResult(intent, 0);? (debugging the code using logcat, I can see the code is definitely executing startActivityForResult)
package com.app.my;
import android.net.Uri;
import android.content.Intent;
import android.app.Activity;
import android.util.Log;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class InstagramStoriesModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
InstagramStoriesModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
//Mandatory function getName that specifies the module name
#Override
public String getName() {
return "InstagramStories";
}
//Custom function that we are going to export to JS
#ReactMethod
public void share(ReadableMap options) {
String stickerImage = "https://www.example.com/image.jpeg";
String backgroundColor = "#000000";
Uri stickerAssetUri = Uri.parse(stickerImage);
Intent intent = new Intent("com.instagram.share.ADD_TO_STORY");
intent.setType("image/jpeg");
intent.putExtra("interactive_asset_uri", stickerAssetUri);
intent.putExtra("top_background_color", backgroundColor);
intent.putExtra("bottom_background_color", backgroundColor);
Activity activity = reactContext.getCurrentActivity();
activity.grantUriPermission("com.instagram.android", stickerAssetUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (activity.getPackageManager().resolveActivity(intent, 0) != null) {
activity.startActivityForResult(intent, 0);
}
}
}
I have an issue with my app that i cant solve. The app takes the input(reminder) from a user and then sets it as a notification. The user can create as many notifications as he/she likes. I want the user to click the notification and get taken to a new activity(Reminder), so he/she can see the reminder in a TextView. So i have an activity(SetReminder), which let the user put his data in a text editor.Then i save his data in a hashMap. The int is the id of user's string data. Then i have a class (AlarmReceiver) which extends BroacastReceiver and generates the notification.In this class i have an id for each notification,which matches the hashMap's int from the SetReminder activity. That way i was expecting that the user would see the data of each notification.But that's doesn't happen. I have multiple Notifications(i want that), but the user sees the data of the last notification, no matter which notifications selects. I am posting the code from the three activities.
Thanks in advance.
SetReminder.class
package demo.push_not_demo;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.SystemClock;
import android.widget.EditText;
import com.kunzisoft.switchdatetime.SwitchDateTimeDialogFragment;
import java.util.HashMap;
public class SetReminder extends AppCompatActivity {
private SwitchDateTimeDialogFragment dateTimeFragment;
Button b1,b2,b3;
EditText editText;
public static int counter=0;
public static HashMap<Integer,String> hashMap;
private static final String TAG_DATETIME_FRAGMENT = "TAG_DATETIME_FRAGMENT";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.set_reminder);
hashMap= new HashMap<Integer, String>();
b1=(Button) findViewById(R.id.set_date_time);
b2=(Button) findViewById(R.id.cancel);
b3=(Button) findViewById(R.id.save);
b1.setOnTouchListener(touch);
b2.setOnTouchListener(touch);
b3.setOnTouchListener(touch);
editText=(EditText) findViewById(R.id.reminder_edit);
}
View.OnTouchListener touch= new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()){
case R.id.set_date_time:
if (event.getAction()==MotionEvent.ACTION_DOWN){
v.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
v.invalidate();
}
else if (event.getAction()== MotionEvent.ACTION_UP){
v.getBackground().clearColorFilter();
v.invalidate();
// Construct SwitchDateTimePicker
dateTimeFragment = (SwitchDateTimeDialogFragment) getSupportFragmentManager().findFragmentByTag(TAG_DATETIME_FRAGMENT);
if(dateTimeFragment == null) {
dateTimeFragment = SwitchDateTimeDialogFragment.newInstance(
getString(R.string.label_datetime_dialog),
getString(R.string.positive_button_datetime_picker),
getString(R.string.negative_button_datetime_picker)
);
}
dateTimeFragment.show(getSupportFragmentManager(), TAG_DATETIME_FRAGMENT);
}
break;
case R.id.cancel:
if (event.getAction()==MotionEvent.ACTION_DOWN){
v.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
v.invalidate();
cancelalarm();
}
else if (event.getAction()== MotionEvent.ACTION_UP){
v.getBackground().clearColorFilter();
v.invalidate();
Intent intent = new Intent(SetReminder.this,HomeScreen.class);
startActivity(intent);
}
break;
case R.id.save:
if (event.getAction()==MotionEvent.ACTION_DOWN){
v.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
v.invalidate();
}
else if (event.getAction()== MotionEvent.ACTION_UP){
v.getBackground().clearColorFilter();
v.invalidate();
counter++;
hashMap.put(counter,editText.getText().toString());
alarmservice();
}
break;
}
return false;
}
};
public void alarmservice(){
Intent intent = new Intent(this,AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(alarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime()+ 5000,pendingIntent);
}
public void cancelalarm(){
Intent intent = new Intent(this,AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
AlertReceiver.class
package demo.push_not_demo;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.widget.EditText;
import java.util.HashMap;
import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH;
import static android.support.v4.app.NotificationCompat.VISIBILITY_PUBLIC;
public class AlertReceiver extends BroadcastReceiver {
public static int id=0;
#Override
public void onReceive(Context context, Intent intent) {
id++;
createNotification(context);
}
private void createNotification(Context context) {
NotificationCompat.Builder notification = new NotificationCompat.Builder(context)
.setAutoCancel(true)
.setSmallIcon(R.drawable.offer1)
.setContentTitle("Notification Title")
.setContentText("Tap to see your reminder")
.setPriority(PRIORITY_HIGH)
.setVibrate(new long[] { 50, 1000, 500, 1000, 1000 })
.setDefaults(DEFAULT_SOUND)
.setVisibility(VISIBILITY_PUBLIC);
Intent intent = new Intent(context,Reminder.class);
PendingIntent pendingintent = PendingIntent.getActivity(context,id,intent,PendingIntent.FLAG_ONE_SHOT);
notification.setContentIntent(pendingintent);
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification ntfc = notification.build();
nm.notify(id,ntfc);
}
}
Reminder.class
package demo.push_not_demo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import static demo.push_not_demo.AlertReceiver.id;
import static demo.push_not_demo.SetReminder.hashMap;
public class Reminder extends AppCompatActivity{
TextView txtv;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reminder);
txtv=(TextView) findViewById(R.id.reminder_textView);
txtv.setText(hashMap.get(id));
}
}
dont use static id,in your code id is always 0. you can check it using Log!
use another way for produce different ids.
when you add notification with same id, the new notification will replace with last notification. use random integer for id
I'm trying to get the Major ID from an iBeacon as a string and pass it to an activity called "LoginActivity.java" so that I can then pass it to my PHP script via Volley POST along with login info username and password, the script will first check if the beacon value is NULL, if so return an error that a beacon is not in range so they cannot log in.
So far I've gotten the Major ID and converted it to a string but I'm getting an error when creating the intent "Cannot resolve constructor". I marked the line where I'm getting the error with <<<<ERROR below. (It's near the end).
package com.mcrlogs.pp.test;
/**
* Created by myuser on 15/01/2017.
*/
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothClass;
import android.content.Context;
import android.content.Intent;
import com.estimote.sdk.Beacon;
import com.estimote.sdk.BeaconManager;
import com.estimote.sdk.Region;
import java.util.List;
import java.util.UUID;
public class BeaconChecker extends Application {
private BeaconManager beaconManager;
public void showNotification(String title, String message) {
Intent notifyIntent = new Intent(this, MainActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivities(this, 0,
new Intent[] { notifyIntent }, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(this)
.setSmallIcon(R.mipmap.security)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build();
notification.defaults |= Notification.DEFAULT_SOUND;
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
}
#Override
public void onCreate() {
super.onCreate();
beaconManager = new BeaconManager(getApplicationContext());
beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
#Override
public void onServiceReady() {
beaconManager.startMonitoring(new Region(
"monitored region",
UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FE6D"),
null, null));
}
});
beaconManager.setMonitoringListener(new BeaconManager.MonitoringListener() {
#Override
public void onEnteredRegion(Region region, List<Beacon> list) {
String iBeaconID = convertIBeaconIDToString(list.get(0).getMajor());
System.out.println(iBeaconID);
showNotification(
"MCR Beacon Detected!",
"Login enabled.");
}
private String convertIBeaconIDToString (int major) {
String iBeaconID = "";
iBeaconID = iBeaconID.concat(Integer.toString(major));
return iBeaconID;
Intent i = new Intent(this, LoginActivity.class); <<<<ERROR
i.putExtra("iBeaconID",iBeaconID);
}
#Override
public void onExitedRegion(Region region) {
// could add an "exit" notification too if you want (-:
}
});
}
}
Try changing:
Intent i = new Intent(this, LoginActivity.class);
To:
Intent i = new Intent(BeaconChecker.this, LoginActivity.class);
This clarifies that the this you refer to is the Application class that satisfies the requirements of the constructor for Intent.