ClassCastException: ActionBarView cannot be cast to TextView - android

I have been using the following workaround to center the activity label (without having to resort to a custom title in XML layout):
((TextView)((FrameLayout)((LinearLayout)((ViewGroup) getWindow().getDecorView()).getChildAt(0)).getChildAt(0)).getChildAt(0)).setGravity(Gravity.CENTER);
This works great but every once in a while I see one of the users (on Google Play) getting a
java.lang.ClassCastException:
com.android.internal.widget.ActionBarView cannot be cast to
android.widget.TextView
These are probably tablet users who are running Android 3.x or higher.
Short of implementing my own custom title that would give me direct access to the activity label, can you recommend another way to avoid that ActionBarView to TextView ClassCastException?
Perhaps check for the Android version under which the app currently runs and go though another level of getChildAt(0)?

The action bar is defined in the theme. So if you want to avoid that ever showing up you need to pick different theme.
Alternatively you can detect what version of OS the user is using and in the case of being 11 (Honeycomb) and higher simply skip the action bar and get the next view.
Which would look something like
if (Integer.valueOf(android.os.Build.VERSION.SDK) > 11)
{
((TextView)((FrameLayout)((LinearLayout)((ViewGroup).getWindow().getDecorView()).getChildAt(1)).getChildAt(0)).getChildAt(0)).setGravity(Gravity.CENTER);
}
else
((TextView)((FrameLayout)((LinearLayout)((ViewGroup).getWindow().getDecorView()).getChildAt(0)).getChildAt(0)).getChildAt(0)).setGravity(Gravity.CENTER);
I would also like to add like Shark said, this is a total hack and is not very robust code. You should be using findViewById() to locate your views and avoid all of that super ugly casting. You can expect your hack or even the code I just put in to break in the future if you continue down that path.

((FrameLayout)((LinearLayout)((ViewGroup) getWindow().getDecorView()).getChildAt(0)).getChildAt(0)).getChildAt(0)
Start collecting child views from here, and search for your own TextView... You just need to skip the actionbar, no need to be nice about it when you started off with a hack anyway.

Related

How to get a seamless transition from app bar to status bar

So I'm currently trying to migrate an app to use Material 3 consistently. Previously it was stiched together without any real design concept. Now I want to actually look like something to take serious.
One thing I haven't been able to figure out is how to give the status bar the same color as the title bar. Currently it looks like this:
The official documentation however lists the seamless version in the "What's new" section:
I'm currently using a LinearLayout with the Theme.Material3.DayNight theme (without any modifications for now) and from what I was able to learn from the documentation I need to make use of components like MaterialToolbar inside a AppBarLayout inside a CoordinatorLayout so everything works as intended. I tried doing that and the scrolling and lifting now works as described in the documentation, but the color of the status bar remains unchanged unfortunately.
I'm not sure at this point if my expectations are wrong or if my code is. I believe that there has to be a built-in mechanism that automatically adjusts the status bar's colour to dynamically match the one of the app bar. I might be wrong though and the material-components-android expects me to implement the logic myself. In any case, could someone point me towards an example implementation where this transition is seamless? This way I could modify my code to implement this behaviour.
I'm currently using com.google.android.material:material:1.5.0 in case this is relevant to the problem.
Thanks in advance!

android lollipop ViewGroup child hierarchy changes?

I have an app that has a minSdk of 15 and I'm working out all the bugs that came with the lollipop upgrade. Our software is very complex and it dynamically creates views using custom ViewGroups and then an array of elements that are explicitly sized and placed inside the group. I'm running into an issue where for example I'll have a ViewGroup and the first child object is a Button...this button is sized to fill the view (not clickable). The second child is a FrameLayout containing a single view. This single view is a video object. In all prior versions of Android this works just fine. The FrameLayout is layered over the button (that is acting as a background) and the video is inside the framelayout. You can interact with the video without any issues.
Something changed in lollipop - suddenly, even though the button is showing up as the 0 index element, it is laying OVER the rest of the children...so I cannot get to the video underneath. If I remove that button element, the video renders and plays just fine...I have no issues interacting with it.
I ran the app in UI Automator Viewer just to make sure I was really setting up the UI as I expected (keep in mind the entire view is dynamically rendered at runtime using image/video assets and xml config files).
I'm not able to share code since this is proprietary software, but I am working on a little test project to see if I can manually recreate the issue with static objects. Once I get that up and running I'll be sure to update this ticket. For now, here is a screenshot of the hierarchy:
https://goo.gl/photos/a8on9CJDnN66XYnV6
Notice the highlighted object, this is the custom ViewGroup, the children below it are what I am describing above.
Does anyone know of a change in Lollipop that would effect the ordering of things? I found earlier that if you have a disabled object but don't have a disabled state drawable assigned to that object it would become invisible, previous versions just used one of the other state drawables..okay that makes sense and it was very easy to fix, but this object is not invisible...so it must be something different.
Any direction would be greatly appreciated.
~A
UPDATE -- FIXED
With the help of #alanv and #BladeCoder I figured out this functionality was due to the new elevation feature of Material design. I was able to fix my particular issue by first checking what version of android the device was using, and if lollipop, I just add this new property to the button:
android:stateListAnimator="#null"
This prevents my explicit child hierarchy from being overridden by the OS.
Lollipop introduced elevation as a way to position the elements on the Z axis and cast shadows between them depending on their difference of elevation.
Enabled buttons have a default elevation of 2dp (and it increases when you press them). So, your button has a higher elevation than the FrameLayout (0dp by default) so it will be drawn on top of it.
Disabled buttons have an elevation of 0dp. That's why disabling the button solved your issue.
Using buttons as backgrounds looks like a bad idea (why not setting a custom Drawable background on your FrameLayout instead?) but if you really need that, you can disable the button like you did and, just to be sure, enforce its elevation to 0dp. Another workaround is to increase the elevation of the FrameLayout but then it may cast a big shadow under Lollipop if it has a background, and maybe that's not what you want.
Okay, UPDATE! I figured out how to fix the issue, although I'm still not sure (even after pouring over the diffs between several classes in grepcode) what changed in lollipop that is causing a change in how this works.
If the button is enabled...and you are placing it using something equivalent to AbsoluteLayout (We have our own ViewGroup we created called Explicit layout, but it does pretty much the same thing as AbsoluteLayout), it will always be on top of anything else in the stack that isn't also a button of some sort (at least that's what I'm finding...I didn't test through every possible widget).
Setting the button that is acting purely as a background image to enabled=false solves this issue. I know, it doesn't make sense that we use Buttons as background images, but our code uses it for dynamic element creation so there are many possible states and uses for each element.
Anyway, not sure if anyone else would even run into this issue, but just in case you do...here it is.
Thanks!

MediaRouter: Detecting a chromecast device when using ActionBarSherlock?

So I modified the Mediarouter source to be dependent on ActionBarSherlock rather than AppCompat. However, now the callback from MediaRouteAdapter onDeviceAvailable(...) is not being called.
Any ideas on how to get this to work?
I don't want to leave the cast button always visible. Rather, I want to use onDeviceAvailable(..) to only make it visible when a device is available.
I found a hack on how to fix this.
If you use appcompat, the cast icon will only be visible when you have a chromecast device in your network, based upon your implementation of onDeviceAvailable(...).
However, if you use ABS, the onDeviceAvailable(...) method is not called when a chromecast device is available on the network. So in order to see the cast icon, we must set it as always visible.
So the issue is that the cast icon is always visible (when you set visibility to visible or when you add it to your actionbar).
HOWEVER:
The MediaRouter has different view states. One for when a cast device is available and one for when there isn't one available.
The Mediarouter library consists of drawable pngs that are the icons for when a device is available or not.
Just replace the one for which 'no route is available' with a blank resource, or anything that suits the app.
When a device is available, the correct cast icon will show, and when not available your custom resource will show (blank if the resource is a blank view).
Here are full details on how to obtain the mediarouter source code, and how to fix this: http://www.droidorbit.com/2013/10/mediarouter-and-actionbarsherlock.html

What layout does the ActionBar use?

I'm trying to do minor tweaks to the layout of items inside an ActionBar, and hitting a lot of problems. It would help if I knew (or even better: could override!) the layout which Android is using for the ActionBar itself.
(Android's layout system doesn't allow you to fully control layout of "items" direct from the item itself - all the options are enabled/disabled based on what type the parent/container layout has)
So, for instance...
try to make a custom ActionView that takes "all remaining space" (because you have no title / don't need a title)
...everything breaks. There are lots of workarounds, all of which have their own bugs (I've tried 3 from SO already, and they all break on different versions of Android / different handsets)
this would be TRIVIAL if I could set the ActionBar's layout to "RelativeLayout" and use "layout_toLeftOf" etc
...but the docs don't seem to answer this, nor do they provide a way of setting it. Any ideas? I don't want to have lots of hardcoded, broken code to workaround the API (because it'll make maintaining this app a nightmare :( )
Have you looked at ActionBarSherlock? It's a support library extension that implements action bar on all versions of Android using single API. Also, when it comes to layouts, I often find it very useful to look at the source code. You can find action bar layouts on the very top of the list here.
Load the view hierarchy and then you will be able to see the views that compose any layout.
http://developer.android.com/tools/debugging/debugging-ui.html

Android - Show App is in Development mode

I have a mobile commerce app and I would like to show in the app that it is running in Development mode or Production mode so that there is no chance of a member of our team accidentally placing an order on the production server.
I had the foresight to derive all my Activity class from a super Activity class where I can add code that will run in all the app's activities. I tried to change the theme here and although the theme changes, I don't quite know how best to indicate the difference.
I would change the text in the TitleBar but my app doesn't have one. The next idea was to change background color of the entire app but some activities have a default color in the layout.
Ideally, I would like text somewhere on the screen saying something like 'dev mode' but I realize that this might be pretty hard to do so I'm up for interesting suggestions.
How about using a ViewStub for development mode?
You can place a ViewStub in each of your layouts where you want to indicate development mode. Your ViewStub can just hold a simple TextView of some sort that says "Development Mode", kind of like a Title bar.
In the code-behind get the reference to the ViewStub and pass it into that common method that runs in each activity. If you are in development mode, inflate the ViewStub.
Take a look at this:
http://developer.android.com/resources/articles/layout-tricks-stubs.html

Categories

Resources