I have created a To-Do List App in Android Studio using Kotlin and wish to add an options menu item that toggles between regular theme and night mode theme. I am following this tutorial
I have entered everything into my existing app but get the error "Unresolved reference: night mode" in my MainActivty.kt file. I am also getting errors "Expecting an element" and "Expecting an expression". My version of Android Studio is 4.2.1. I am attaching the code from the MainActivity.kt, main_menu.xml, and strings.xml.
MainActivity.kt
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
intent nightMode = AppCompatDelegate.getDefaultNightMode()
if (nightMode == AppCompatDelegate.MODE_NIGHT_YES){
menu?.findItem(R.id.night_mode)?.setTitle(R.string.day_mode)
} else{
menu?.findItem(R.id.night_mode)?.setTitle(R.string.night_mode)
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId ==R.id.night_mode){
intent nightMode = AppCompatDelegate.getDefaultNightMode()
if (nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_NO)
} else {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES)
}
}
recreate()
return true
}
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/night_mode"
android:title="#string/night_mode>"/>
</menu>
strings.xml
<resources>
<string name="app_name">To do List</string>
<string name="night_mode">Night Mode</string>
<string name="day_mode">Day Mode</string>
</resources>
intent nightMode is not a valid expression.
The original tutorial Java code seems to have int nightMode there, declaring a variable of type int (as in integer).
In kotlin you can declare a variable with val (immutable) or var (mutable).
So, change the intent to val.
Related
I am developing an app using Xamarin.Forms and I am trying to insert the splash screen to my Android project.
I found a few tutorials for creating a splash screen with a background color and a static png image, but I want to use my svg animation as splash screen. I thought I could follow a tutorial for static image and just replace the png image with the svg animation, but it didn't work. Here's what I have so far:
On SplashActivity.cs:
[Activity(Label = "SplashActivity", Theme = "#style/Theme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
}
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
async void SimulateStartup()
{
await Task.Delay(5000);
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
}
On MainActivity.cs:
// I only changed the MainLauncher property to false
[Activity(Label = "MyApp", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
...
}
On styles.xml (in the Xamarin.Android project):
<style name="Theme.Splash" parent="android:Theme">
<item name="android:windowBackground">#drawable/desenhando5s</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<item name="colorPrimaryDark">#004632</item>
</style>
When I run the application, it only shows a black screen as splash screen and then shows my login page as always.
Can anybody tell me what I have to do to set my animation as the splash screen?
(FYI: in case anyone wants to know, I created the animation using SVGator)
You could use FFImageLoading to load your svg image in your SplashActivity instead of set it in styles.xml.
Splash screen:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FFImageLoading.Views.ImageViewAsync
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Code:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.layout5);
var filePath = "check";
var imageView = FindViewById<ImageView>(Resource.Id.imageView);
ImageService.Instance.LoadCompiledResource(filePath).WithCustomDataResolver(new SvgDataResolver(64, 0, true)).Into(imageView);
}
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
async void SimulateStartup()
{
await Task.Delay(5000);
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
Updated:
Please check the screenshot. The .svg image is in the drawable folder. The layout5 is the splash screen in the layout folder.
I've created three activities. My first MainActivity has two buttons, one that takes you to Activity2 and one that takes you to Activity3. Both of those buttons work, I've managed to code them correctly.
But then on Activity3 there's a button that's supposed to take you also to Activity2, and it's not working. I've tried several things but I can't seem to figure it out. Is it possible to code several buttons that lead to the same activity? If so please help cause I'm new at coding and stuff. Also here's how I've been coding the buttons :
1-after creating the activity, I go to the Java file and create a new class. In that class I write the following code :
class className : AppCompatActivity(){
override fun onCreate (savedInstance : Bundle?){
super.onCreate(savedInstance)
setContentView(R.layout.activity2)
}
}
Then I add it to the manifest
2-then I go back to the MainActivity and write this :
val anyName = buttonName
anyName.setOnClickListener {
startActivity(Intent(this, class Name :: class.java))
}
Of course android studio takes care of everything and imports everything that's needed but the second I add more than two of those in my MainActivity the whole app crashes.
Please explain this as simply as possible as, again, I'm really new to coding and android studio.
Thank you !
To go back on an activity you can just use finish() on any function, but if you want to take any information with you, you should look for more information about startActivityforResult().
However next time upload the code and not this pseudocode please, it would help a lot!
When you creating a new activity, you need also to add to it the new XML file, which will be display UI in the Activity page.
You can do it in two ways:
1. Custom.
Create a new ClassName.kt (Java.class in Java) and attach inside onCreate() method a XML layout, which will displaying all views in Activity page.
2. With Android Studio.
Just right-click in your package name folder, where appears your, for example, empty activity when you start new an Android Studio Project. Then select new, then in bottom side of drop-downed view select type of new activity what you want. For example, it is Empty Activity. So, lets sum above information: right-click at your package name folder -> new -> type of activity.
For what below info? I see in your example code, which you show as code in Activity number 3, what you have in onCreate() this line of code setContentView(R.layout.activity2). It is line means, what you add XML file into your activity. One XML file for activity can be used only for one activity if you want to show, after click on button another activity. Rather you will see only one screen because two activities use one layout. So, check your activities
need to be something like this:
1.In ActivityOne.
class ActivityOne : Activity() {
override fun onCreate (savedInstance : Bundle?) {
super.onCreate(savedInstance)
setContentView(R.layout.activity1)
}
}
1.In ActivityTwo.
class ActivityOne : Activity() {
override fun onCreate (savedInstance : Bundle?) {
super.onCreate(savedInstance)
setContentView(R.layout.activity2)
}
}
1.In ActivityThree.
class ActivityThree : Activity() {
override fun onCreate (savedInstance : Bundle?) {
super.onCreate(savedInstance)
setContentView(R.layout.activity3)
}
}
Make sure if you want to create a new activity First right click app then goto new -> Activity -> Empty Activity .
finally you can add onClick in your Button tag , then use startActivity method.
public void methodName(View view) {
startActivity(new Intent(this,ActivityName.class));
}
Example Code:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void gotoTwo(View view) {
startActivity(new Intent(this,Activity2.class));
}
public void gotoThree(View view) {
startActivity(new Intent(this,Activity3.class));
}
}
activity_main.xml :
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="200dp"
android:layout_marginRight="240dp"
android:onClick="gotoTwo"
android:text="Activity2" />
Don`t forgot to create a new java you should create a new xml file too
I followed the InMobi guidelines for Android apps step by step but got the following exception from
DataBindingUtil.setContentView(this, R.layout.mainActivity):
Binary XML file line #670: Binary XML file line #670: Error inflating
class com.inmobi.ads.InMobiBanner
<LinearLayout
xmlns:inmobi="http://schemas.android.com/apk/lib/com.inmobi.ads"
android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView android:text="Ad"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.inmobi.ads.InMobiBanner
android:id="#+id/bannerAdInMobi"
android:layout_width="320dp"
android:layout_height="50dp"
inmobi:placementId="plid-1526902340491"
inmobi:refreshInterval="60" />
</LinearLayout>
Could anyone offer a tip on how to diagnose it?
Since no one answered after a month, let me post mine.
InMobil's support has kindly helped me find the culprit - layout inflation before InMobiSdk.init(). An app needs to run InMobiSdk.init() before inflating the layout.
My app cannot do this because it uses InMobil ads only under certain conditions (e.g. only the FREE version has ads), so I have removed com.inmobi.ads.InMobiBanner from the layout, and add it in Java code when it is needed.
Ok I Solved this problem . just follow these steps ->
Step 1: Declare the variable in your Activity/fragment
private lateinit var bannerAd: InMobiBanner
Step 2: Initialite InMobiSDK in onCreate()
override fun onCreate(savedInstanceState: Bundle?) {
bannerAd= Helper.InitializInMobiAds(requireContext())
super.onCreate(savedInstanceState)
}
Step 3: here is InitializInMobiAds() method in Helper Class
fun InitializInMobiAds(context: Context): InMobiBanner{
val consentObject = JSONObject()
try {
// Provide correct consent value to sdk which is obtained by User
consentObject.put(InMobiSdk.IM_GDPR_CONSENT_AVAILABLE, false)
// Provide 0 if GDPR is not applicable and 1 if applicable
consentObject.put("gdpr", "0")
// Provide user consent in IAB format
// consentObject.put(InMobiSdk.IM_GDPR_CONSENT_IAB, “ << consent in IAB format >> ”)
} catch (e: JSONException) {
e.printStackTrace()
}
InMobiSdk.init(context, "AcountIdHere" , consentObject, SdkInitializationListener() {
#Override
fun onInitializationComplete(error : Error?) {
if (null != error) {
Log.e("", "InMobi Init failed -" + error.message.toString())
} else {
Log.d("", "InMobi Init Successful")
}
}
})
return InMobiBanner(context, PLID_here)
}
Step 4: now use .load() method in onCreateView() or in whichever block which runs after onCreate()
binding.adView.load()
I have tried webview with Android studio and FB share and other social media share buttons are working fine. But FB direct like and comment button on my website is not working. When I press like button I can see white screen with left top screen number "1". Please kindly help me.
MainActivity.Java
package com.example.neermaicom;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.WindowManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import static android.content.Intent.*;
public class MainActivity extends AppCompatActivity {
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
webView = findViewById(R.id.webview);
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url == null || url.startsWith("http://") || url.startsWith("https://")) return false;
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
} catch (Exception e) {
return true;
}
}
});
webView.loadUrl("http://www.neermai.com");
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
}
//This method require to use back button if want to go previous web page
#Override
public void onBackPressed() {
if(webView.canGoBack()){
webView.goBack();
}else {
super.onBackPressed();
}
}
Activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="#+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
This is due to the Facebook user auth, unfortunately android webview is not fully compatible with auth systems, an alternative that I use in my webview applications is to use "Chrome Custom Tabs" to auth access to the system of comments that I use.
In my application when the user clicks on comment, a Google Chrome tab is opened inside my application showing the comments page, when the user is not logged, the chrome auth the user without having to close or minimize my application to open google chrome. Everything is done within my own application.
To start the Chrome Tab when I added an "Intent" to shouldOverrideUrlLoading, below is an example of my code.
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("#comments")){
Uri uri = Uri.parse(url);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.build().launchUrl(PostActivity.this, uri);
return true;
}
else {
view.loadUrl(url);
return true;
}
}
And in Gradle app:
implementation 'androidx.browser:browser:1.3.0-alpha01'
My url for comment pages has "#comments" you change to something standard that you have in your comment page URLs or if the facebook comment system is directly on the post page, put something that is standard in the url of your posts to open in the google chrome tab.
Scan Bluetooth Devices not working on Android Things DP3. Any idea/workaround? Not getting action BluetoothDevice.ACTION_FOUND.
I've added ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permisssion due changes in Android 6.0 but still not working.
https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html
Also android.permission.BLUETOOTH_ADMIN, android.permission.BLUETOOTH
I have checked, ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION over Android >=6.0 needs runtime permission but it give an error due Android Things limitation.
private void checkPermission() {
List<String> permissionsList = new ArrayList<String>();
List<String> permissionsNeeded = new ArrayList<String>();
// app
permissionsList.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
permissionsList.add(Manifest.permission.ACCESS_WIFI_STATE);
permissionsList.add(Manifest.permission.SET_TIME_ZONE);
// AndroidThingsLib
permissionsList.add(Manifest.permission.BLUETOOTH_ADMIN);
permissionsList.add(Manifest.permission.BLUETOOTH);
permissionsList.add(Manifest.permission.CHANGE_WIFI_STATE);
permissionsList.add(Manifest.permission.INTERNET);
permissionsList.add(Manifest.permission.ACCESS_NETWORK_STATE);
for (int i = 0; i < permissionsList.size(); i++){
if (checkSelfPermission(permissionsList.get(i)) == PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(permissionsList.get(i));
updateDataLogs(SourceEnum.System, "GRANTED: " + permissionsList.get(i));
} else {
permissionsNeeded.add(permissionsList.get(i));
updateDataLogs(SourceEnum.Error, "NOT GRANTED: " + permissionsList.get(i));
}
}
if (permissionsList.size()>0){
requestPermissions(permissionsNeeded.toArray(new String[permissionsNeeded.size()]),5678);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 5678){
for (int i = 0; i < permissions.length; i++){
updateDataLogs(SourceEnum.Error, permissions[i] + " result " + grantResults[i]);
}
}
}
private void enableBluetoothScan() {
updateDataLogs(SourceEnum.System, "enableBluetoothScan");
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter.isEnabled()){
bluetoothAdapter.startDiscovery();
} else {
updateDataLogs(SourceEnum.Error, "Bluetooth Adapter not enabled");
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
updateDataLogs(SourceEnum.System, "DISCOVERY STARTED");
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
updateDataLogs(SourceEnum.System, "DISCOVERY FINISHED");
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
updateDataLogs(SourceEnum.System, "NEW DEVICE " + device.getName());
}
}
}
};
As noted in the Platform Overview, runtime permissions granting is not supported on Android Things because the device may not have an interactive display to show the dialog. Instead, Android Things falls back on the install-time permissions model for all permissions requested in the manifest. This means calls to methods like requestPermissions() aren't necessary and won't help you.
Regarding issues encountered during the current preview, the following excerpt is from the Release Notes:
Dangerous permissions requested by apps are not granted until the next device reboot. This includes new app installs and new elements in existing apps.
For the time being, when your app requests dangerous permissions (like location permissions), you need to reboot the device after install (one-time) to have those permissions granted during boot.
Thanks to your explanation what you did already, I was able to conquer this issue. Because you did not mark the question as solved yet:
build.gradle (app; thanks to 1 and 2):
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
<!-- update this to your version of the Android SDK Tools -->
buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion 24
}
}
dependencies {
<!-- update this to your version of Android Things -->
provided 'com.google.android.things:androidthings:0.4-devpreview'
}
AndroidManifest.xml (thanks to 1 and 2):
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=" . . . ">
<!-- required for getState in startDiscovery -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- required for startDiscovery -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- required for the IntentFilter ACTION_FOUND -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- change to your label -->
<application android:label="Intel Edison">
<uses-library android:name="com.google.android.things"/>
<!-- change to the name of your Main Activity -->
<activity android:name=".HomeActivity">
<!-- Launch activity as default from Android Studio -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Launch activity automatically on boot -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.IOT_LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
HomeActivity.java:
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
registerReceiver(mReceiverBT, filter);
BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
boolean started = mBtAdapter.startDiscovery();
if (false == started) {
<!-- in that case, catch BluetoothAdapter.STATE_ON in the receiver and start the Bluetooth Discovery then -->
mBtAdapter.enable();
}
With this code, my app started right away after booting the Intel Edison board and was able to discover nearby Bluetooth devices. Notes:
On this board, Android Things requires 69 seconds (Developer Preview 4) or 82 seconds (Developer Preview 3) to start my app.
In logcat, I saw "Not granting permission android.permission.ACCESS_COARSE_LOCATION to package … because it was previously installed without". I found no way around that; reported in Issue 62514750.
Actually, you might not need any ‘dangerous’ permission at all – for example, I do nothing on ACTION_FOUND – because ACTION_NANE_CHANGED is fired always here in my scenarios; reported in Issue 62524160.