Get theme attributes programmatically - android

How do I get the value of a Theme attribute programmatically?
For example:
Theme:
<style name="Theme">
... truncated ....
<item name="textAppearanceLarge">#android:style/TextAppearance.Large</item>
</style>
Code:
int textSize = ???? // how do I get Theme.textAppearanceLarge?
EDIT: too many answers that don't address the question.

use this function :
myView.setTextAppearance(Context context, int resid)
//Sets the text color, size, style, hint color, and highlight color from the specified TextAppearance resource.
see : http://developer.android.com/reference/android/widget/TextView.html#setTextAppearance%28android.content.Context,%20int%29
From TextView.java this is what the above function does:
public void setTextAppearance(Context context, int resid) {
TypedArray appearance =
context.obtainStyledAttributes(resid,
com.android.internal.R.styleable.TextAppearance);
int color;
ColorStateList colors;
int ts;
.
.
.
ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
TextAppearance_textSize, 0);
if (ts != 0) {
setRawTextSize(ts);
}
int typefaceIndex, styleIndex;
typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
TextAppearance_typeface, -1);
styleIndex = appearance.getInt(com.android.internal.R.styleable.
TextAppearance_textStyle, -1);
setTypefaceByIndex(typefaceIndex, styleIndex);
appearance.recycle();
}
This is another way of doing this. Do make sure you recycle the appearance (TypedArray obect). Hope this helps!

This should do the trick:
int textAppearance = android.R.attr.textAppearanceLarge;
myTextView.setTextAppearance(context, textAppearance);

I ended up with the following code:
public class TextAppearanceConsts
{
private static final String LOG_TAG = "TextAppearanceConsts";
public static final int[] styleable_TextAppearance;
public static final int styleable_TextAppearance_textColor;
public static final int styleable_TextAppearance_textSize;
public static final int styleable_TextAppearance_typeface;
public static final int styleable_TextAppearance_fontFamily;
public static final int styleable_TextAppearance_textStyle;
static {
// F*ing freaking code
int ta[] = null, taTc = 0, taTs = 0, taTf = 0, taFf = 0, taTst = 0;
try{
Class<?> clazz = Class.forName("com.android.internal.R$styleable", false, TextAppearanceConsts.class.getClassLoader());
ta = (int[])clazz.getField("TextAppearance").get(null);
taTc = getField(clazz, "TextAppearance_textColor");
taTs = getField(clazz, "TextAppearance_textSize");
taTf = getField(clazz, "TextAppearance_typeface");
taFf = getField(clazz, "TextAppearance_fontFamily");
taTst = getField(clazz, "TextAppearance_textStyle");
}catch(Exception e){
Log.e(LOG_TAG, "Failed to load styleable_TextAppearance", e);
}
styleable_TextAppearance = ta;
styleable_TextAppearance_textColor = taTc;
styleable_TextAppearance_textSize = taTs;
styleable_TextAppearance_typeface = taTf;
styleable_TextAppearance_fontFamily = taFf;
styleable_TextAppearance_textStyle = taTst;
}
private static int getField(Class<?> clazz, String fieldName)
throws IllegalAccessException
{
try{
return clazz.getField(fieldName).getInt(null);
}catch(NoSuchFieldException nsfe){
Log.e(LOG_TAG, nsfe.toString());
return -1;
}
}
}
Usage example:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RangeBar, 0, 0);
TypedArray appearance = null;
int ap = ta.getResourceId(R.styleable.RangeBar_textAppearance, -1);
if (ap != -1) {
appearance = context.getTheme().obtainStyledAttributes(ap, TextAppearanceConsts.styleable_TextAppearance);
int n = appearance.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = appearance.getIndex(i);
if (attr == TextAppearanceConsts.styleable_TextAppearance_textColor){
mTextColor = appearance.getColorStateList(attr);
} else if (attr == TextAppearanceConsts.styleable_TextAppearance_textSize){
mTextSize = appearance.getDimensionPixelSize(attr, mTextSize);
} else if (attr == TextAppearanceConsts.styleable_TextAppearance_typeface){
mTypefaceIndex = appearance.getInt(attr, -1);
} else if (attr == TextAppearanceConsts.styleable_TextAppearance_fontFamily){
mFontFamily = appearance.getString(attr);
} else if (attr == TextAppearanceConsts.styleable_TextAppearance_textStyle){
mFontStyleIndex = appearance.getInt(attr, -1);
} else {
....
}
}
appearance.recycle();
}
The R.styleable.RangeBar_textAppearance is my attribute, but you can access Android attributes this way:
final static String ANDROID_NS = "http://schemas.android.com/apk/res/android";
final int textAppearanceResId = attrs.getAttributeResourceValue(ANDROID_NS, "textAppearance", 0);
....
int ap = ta.getResourceId(textAppearanceResId, -1);
I know the method is some kind of hacking, but don't know any other better one :(

Related

How to handle notch(display cutout) in android API lower than 28?

Android added notch support on API 28, but how to handle it on devices running API 27 (Honor 10, Huawei P20, etc.) ?
I was trying to use DisplayCutoutCompat but I was not able to create an instance of it since documentation does not really point out how create one.
How to create the constructor parameter values: Rect safeInsets, List<Rect> boundingRects?
I also looked into the source code of the constructor, which is a bit confusing to me:
public DisplayCutoutCompat(Rect safeInsets, List<Rect> boundingRects) {
this(SDK_INT >= 28 ? new DisplayCutout(safeInsets, boundingRects) : null);
}
This will always return null on devices running API < 28.
Thank you in advance.
Google provided notch related APIs in Android P. Devices with notch and API version lower than P implemented their own notch APIs.You can consult the APIs from device specified documentation.
Also I did not see creation of DisplayCutoutCompat instance in official documentation, but you can create DisplayCutout as follow:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
DisplayCutout displayCutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
}
So you want to handle notch(display cutout) in android API lower than 28. That's horrible because different manufactures has different implementations. Nevertheless, all use Java reflection to get notch information. Factory design pattern should be used here.
interface ICutout {
public boolean hasCutout();
public Rect[] getCutout();
}
Huawei display cutout
private static class HuaweiCutout implements ICutout {
private Context context;
public HuaweiCutout(#NonNull Context context) {
this.context = context;
}
#Override
public boolean hasCutout() {
try {
ClassLoader classLoader = context.getClassLoader();
Class class_HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method_hasNotchInScreen = class_HwNotchSizeUtil.getMethod("hasNotchInScreen");
return (boolean) method_hasNotchInScreen.invoke(class_HwNotchSizeUtil);
} catch (Exception e) {
}
return false;
}
#Override
public Rect[] getCutout() {
try {
ClassLoader classLoader = context.getClassLoader();
Class class_HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method_getNotchSize = class_HwNotchSizeUtil.getMethod("getNotchSize");
int[] size = (int[]) method_getNotchSize.invoke(class_HwNotchSizeUtil);
int notchWidth = size[0];
int notchHeight = size[1];
int screenWidth = DeviceUtil.getScreenWidth(context);
int x = (screenWidth - notchWidth) >> 1;
int y = 0;
Rect rect = new Rect(x, y, x + notchWidth, y + notchHeight);
return new Rect[] {rect};
} catch (Exception e) {
}
return new Rect[0];
}}
Oppo display cutout
private static class OppoCutout implements ICutout {
private Context context;
public OppoCutout(#NonNull Context context) {
this.context = context;
}
#Override
public boolean hasCutout() {
String CutoutFeature = "com.oppo.feature.screen.heteromorphism";
return context.getPackageManager().hasSystemFeature(CutoutFeature);
}
#Override
public Rect[] getCutout() {
String value = SystemProperties.getProperty("ro.oppo.screen.heteromorphism");
String[] texts = value.split("[,:]");
int[] values = new int[texts.length];
try {
for(int i = 0; i < texts.length; ++i)
values[i] = Integer.parseInt(texts[i]);
} catch(NumberFormatException e) {
values = null;
}
if(values != null && values.length == 4) {
Rect rect = new Rect();
rect.left = values[0];
rect.top = values[1];
rect.right = values[2];
rect.bottom = values[3];
return new Rect[] {rect};
}
return new Rect[0];
}}
Vivo display cutout
private static class VivoCutout implements ICutout {
private Context context;
public VivoCutout(#NonNull Context context) {
this.context = context;
}
#Override
public boolean hasCutout() {
try {
ClassLoader clazz = context.getClassLoader();
Class ftFeature = clazz.loadClass("android.util.FtFeature");
Method[] methods = ftFeature.getDeclaredMethods();
for(Method method: methods) {
if (method.getName().equalsIgnoreCase("isFeatureSupport")) {
int NOTCH_IN_SCREEN = 0x00000020; // 表示是否有凹槽
int ROUNDED_IN_SCREEN = 0x00000008; // 表示是否有圆角
return (boolean) method.invoke(ftFeature, NOTCH_IN_SCREEN);
}
}
} catch (Exception e) {
}
return false;
}
#Override
public Rect[] getCutout() {
// throw new RuntimeException(); // not implemented yet.
return new Rect[0];
}}
Xiaomi display cutout of Android Oreo, of Android Pie
private static class XiaomiCutout implements ICutout {
private Context context;
public XiaomiCutout(#NonNull Context context) {
this.context = context;
}
#Override
public boolean hasCutout() {
// `getprop ro.miui.notch` output 1 if it's a notch screen.
String text = SystemProperties.getProperty("ro.miui.notch");
return text.equals("1");
}
#Override
public Rect[] getCutout() {
Resources res = context.getResources();
int widthResId = res.getIdentifier("notch_width", "dimen", "android");
int heightResId = res.getIdentifier("notch_height", "dimen", "android");
if(widthResId > 0 && heightResId > 0) {
int notchWidth = res.getDimensionPixelSize(widthResId);
int notchHeight = res.getDimensionPixelSize(heightResId);
// one notch in screen top
int screenWidth = DeviceUtil.getScreenSize(context).getWidth();
int left = (screenWidth - notchWidth) >> 1;
int right = left + notchWidth;
int top = 0;
int bottom = notchHeight;
Rect rect = new Rect(left, top, right, bottom);
return new Rect[] {rect};
}
return new Rect[0];
}}
For SystemProperties class, you can read this thread, actually it calls adb shell getprop <property_name>.
In case some manufactures' not coming up with a getNotchHeight() method, you can just use the status bar's height. Android has guarantee that notch height is at most the status bar height.
public static int getStatusBarHeight(Context context) {
int statusBarHeight = 0;
Resources res = context.getResources();
int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = res.getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
For Android Pie and above (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P), you can use system's API to get notch information. Note the window must be attachedActivity#onAttachedToWindow or you will get null DisplayCutout.
DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
I had similar issue, and had to use reflection to access what I need.
My problem was that I had some calculations depending on screen size and while not accessing the notch space, the calculations were wrong and code didn't work well.
public static final String CLASS_DISPLAY_CUTOUT = "android.view.DisplayCutout";
public static final String METHOD_GET_DISPLAY_CUTOUT = "getDisplayCutout";
public static final String FIELD_GET_SAFE_INSET_TOP = "getSafeInsetTop";
public static final String FIELD_GET_SAFE_INSET_LEFT = "getSafeInsetLeft";
public static final String FIELD_GET_SAFE_INSET_RIGHT = "getSafeInsetRight";
public static final String FIELD_GET_SAFE_INSET_BOTTOM = "getSafeInsetBottom";
try {
WindowInsets windowInsets = activity.getWindow().getDecorView().getRootWindowInsets();
if (windowInsets == null) {
return;
}
Method method = WindowInsets.class.getMethod(METHOD_GET_DISPLAY_CUTOUT);
Object displayCutout = method.invoke(windowInsets);
if (displayCutout == null) {
return;
}
Class clz = Class.forName(CLASS_DISPLAY_CUTOUT);
int top = (int) clz.getMethod(FIELD_GET_SAFE_INSET_TOP).invoke(displayCutout);
int left = (int) clz.getMethod(FIELD_GET_SAFE_INSET_LEFT).invoke(displayCutout);
int right = (int) clz.getMethod(FIELD_GET_SAFE_INSET_RIGHT).invoke(displayCutout);
int bottom = (int) clz.getMethod(FIELD_GET_SAFE_INSET_BOTTOM).invoke(displayCutout);
Rect rect = new Rect(left, top, right, bottom);
} catch (Exception e) {
Log.e(TAG, "Error when getting display cutout size");
}
To handle API lower then 28 WindowInsetsCompat can be used. Kotlin example:
WindowInsetsCompat.toWindowInsetsCompat(window.decorView.rootWindowInsets).displayCutout

Justify text inside Android Textview

I want to Justify text inside Android TextView. With copy and share function and can accept spannable string. Can someone help me. It's so important for me. Thank you in advance
I have a solution for the text-justify in Android.
I have created a Custom Textview class, with this you can solve the justification issue in Android.
<com.trailcreator.util.JustifyCustomTextView
android:id="#+id/yourTextViewID"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is the class
public class JustifyCustomTextView extends android.support.v7.widget.AppCompatTextView {
//Object that helps us to measure the words and characters like spaces.
private Paint mPaint;
//Thin space (Hair Space actually) character that will fill the spaces
private String mThinSpace = "\u200A";
//String that will storage the text with the inserted spaces
private String mJustifiedText = "";
//Float that represents the actual width of a sentence
private float mSentenceWidth = 0;
//Integer that counts the spaces needed to fill the line being processed
private int mWhiteSpacesNeeded = 0;
//Integer that counts the actual amount of words in the sentence
private int mWordsInThisSentence = 0;
//ArrayList of Strings that will contain the words of the sentence being processed
private ArrayList<String> mTemporalLine = new ArrayList<String>();
//StringBuilder that will hold the temporal chunk of the string to calculate word index.
private StringBuilder mStringBuilderCSequence = new StringBuilder();
//List of SpanHolder class that will hold the spans within the giving string.
private List<SpanHolder> mSpanHolderList = new ArrayList<>();
//StringBuilder that will store temp data for joining sentence.
private StringBuilder sentence = new StringBuilder();
private int mViewWidth;
private float mThinSpaceWidth;
private float mWhiteSpaceWidth;
//Default Constructors!
public JustifyCustomTextView(Context context) {
super(context);
}
public JustifyCustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public JustifyCustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mJustifiedText.replace(" ", "")
.replace("", mThinSpace)
.equals(this.getText().toString().replace(" ", "").replace("", mThinSpace))) {
return;
}
ViewGroup.LayoutParams params = this.getLayoutParams();
CharSequence charSequence = this.getText();
mSpanHolderList.clear();
String[] words = this.getText().toString().split(" ");
//Get spans within the string and adds the instance references into the
//SpanHolderList to be applied once the justify process has been performed.
SpannableString s = SpannableString.valueOf(charSequence);
if ((charSequence instanceof SpannedString)) {
for (int i = 0; i < this.getText().length() - 1; i++) {
CharacterStyle[] spans =
((SpannedString) charSequence).getSpans(i, i + 1, CharacterStyle.class);
if (spans != null && spans.length > 0) {
for (CharacterStyle span : spans) {
int spaces =
charSequence.toString().substring(0, i).split(" ").length + charSequence.toString()
.substring(0, i)
.split(mThinSpace).length;
SpanHolder spanHolder =
SpanHolder.getNewInstance(spans, s.getSpanStart(span), s.getSpanEnd(span), spaces);
mStringBuilderCSequence.setLength(0);
for (int j = 0; j <= words.length - 1; j++) {
mStringBuilderCSequence.append(words[j]);
mStringBuilderCSequence.append(" ");
if (mStringBuilderCSequence.length() > i) {
if (words[j].trim().replace(mThinSpace, "").length() == 1) {
spanHolder.setWordHolderIndex(j);
} else {
spanHolder.setWordHolderIndex(j);
spanHolder.setTextChunkPadded(true);
}
break;
}
}
mSpanHolderList.add(spanHolder);
}
}
}
}
mPaint = this.getPaint();
mViewWidth = this.getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
//This class won't justify the text if the TextView has wrap_content as width
//And won't repeat the process of justify text if it's already done.
//AND! won't justify the text if the view width is 0
if (params.width != ViewGroup.LayoutParams.WRAP_CONTENT
&& mViewWidth > 0
&& words.length > 0
&& mJustifiedText.isEmpty()) {
mThinSpaceWidth = mPaint.measureText(mThinSpace);
mWhiteSpaceWidth = mPaint.measureText(" ");
for (int i = 0; i <= words.length - 1; i++) {
boolean containsNewLine = (words[i].contains("\n") || words[i].contains("\r"));
if (containsNewLine) {
String[] splitted = words[i].split("(?<=\\n)");
for (String splitWord : splitted) {
processWord(splitWord, splitWord.contains("\n"));
}
} else {
processWord(words[i], false);
}
}
mJustifiedText += joinWords(mTemporalLine);
}
//Apply the extra spaces to the items of the SpanList that were added due
//the justifying process.
SpannableString spannableString = SpannableString.valueOf(mJustifiedText);
for (SpanHolder sH : mSpanHolderList) {
int spaceCount = 0, wordCount = 0;
boolean isCountingWord = false;
int j = 0;
while (wordCount < (sH.getWordHolderIndex() + 1)) {
if (mJustifiedText.charAt(j) == ' ' || mJustifiedText.charAt(j) == ' ') {
spaceCount++;
if (isCountingWord) {
wordCount++;
}
isCountingWord = false;
} else {
isCountingWord = true;
}
j++;
}
sH.setStart(
sH.getStart() + spaceCount - sH.getCurrentSpaces() + (sH.isTextChunkPadded() ? 1 : 0));
sH.setEnd(
sH.getEnd() + spaceCount - sH.getCurrentSpaces() + (sH.isTextChunkPadded() ? 1 : 0));
}
//Applies spans on Justified String.
for (SpanHolder sH : mSpanHolderList) {
for (CharacterStyle cS : sH.getSpans())
spannableString.setSpan(cS, sH.getStart(), sH.getEnd(), 0);
}
if (!mJustifiedText.isEmpty()) this.setText(spannableString);
}
private void processWord(String word, boolean containsNewLine) {
if ((mSentenceWidth + mPaint.measureText(word)) < mViewWidth) {
mTemporalLine.add(word);
mWordsInThisSentence++;
mTemporalLine.add(containsNewLine ? "" : " ");
mSentenceWidth += mPaint.measureText(word) + mWhiteSpaceWidth;
if (containsNewLine) {
mJustifiedText += joinWords(mTemporalLine);
resetLineValues();
}
} else {
while (mSentenceWidth < mViewWidth) {
mSentenceWidth += mThinSpaceWidth;
if (mSentenceWidth < mViewWidth) mWhiteSpacesNeeded++;
}
if (mWordsInThisSentence > 1) {
insertWhiteSpaces(mWhiteSpacesNeeded, mWordsInThisSentence, mTemporalLine);
}
mJustifiedText += joinWords(mTemporalLine);
resetLineValues();
if (containsNewLine) {
mJustifiedText += word;
mWordsInThisSentence = 0;
return;
}
mTemporalLine.add(word);
mWordsInThisSentence = 1;
mTemporalLine.add(" ");
mSentenceWidth += mPaint.measureText(word) + mWhiteSpaceWidth;
}
}
//Method that resets the values of the actual line being processed
private void resetLineValues() {
mTemporalLine.clear();
mSentenceWidth = 0;
mWhiteSpacesNeeded = 0;
mWordsInThisSentence = 0;
}
//Function that joins the words of the ArrayList
private String joinWords(ArrayList<String> words) {
sentence.setLength(0);
for (String word : words) {
sentence.append(word);
}
return sentence.toString();
}
//Method that inserts spaces into the words to make them fix perfectly in the width of the view. I know I'm a genius naming stuff :)
private void insertWhiteSpaces(int whiteSpacesNeeded, int wordsInThisSentence,
ArrayList<String> sentence) {
if (whiteSpacesNeeded == 0) return;
if (whiteSpacesNeeded == wordsInThisSentence) {
for (int i = 1; i < sentence.size(); i += 2) {
sentence.set(i, sentence.get(i) + mThinSpace);
}
} else if (whiteSpacesNeeded < wordsInThisSentence) {
for (int i = 0; i < whiteSpacesNeeded; i++) {
int randomPosition = getRandomEvenNumber(sentence.size() - 1);
sentence.set(randomPosition, sentence.get(randomPosition) + mThinSpace);
}
} else if (whiteSpacesNeeded > wordsInThisSentence) {
//I was using recursion to achieve this... but when you tried to watch the preview,
//Android Studio couldn't show any preview because a StackOverflow happened.
//So... it ended like this, with a wild while xD.
while (whiteSpacesNeeded > wordsInThisSentence) {
for (int i = 1; i < sentence.size() - 1; i += 2) {
sentence.set(i, sentence.get(i) + mThinSpace);
}
whiteSpacesNeeded -= (wordsInThisSentence - 1);
}
if (whiteSpacesNeeded == 0) return;
if (whiteSpacesNeeded == wordsInThisSentence) {
for (int i = 1; i < sentence.size(); i += 2) {
sentence.set(i, sentence.get(i) + mThinSpace);
}
} else if (whiteSpacesNeeded < wordsInThisSentence) {
for (int i = 0; i < whiteSpacesNeeded; i++) {
int randomPosition = getRandomEvenNumber(sentence.size() - 1);
sentence.set(randomPosition, sentence.get(randomPosition) + mThinSpace);
}
}
}
}
//Gets a random number, it's part of the algorithm... don't blame me.
private int getRandomEvenNumber(int max) {
Random rand = new Random();
// nextInt is normally exclusive of the top value,
return rand.nextInt((max)) & ~1;
}
}
public class SpanHolder {
private CharacterStyle[] spans;
private int start;
private int end;
private boolean textChunkPadded =false;
private int wordHolderIndex;
private int currentSpaces;
public SpanHolder(CharacterStyle[] spans, int start, int end, int spaces){
this.setSpans(spans);
this.setStart(start);
this.setEnd(end);
this.setCurrentSpaces(spaces);
}
public static SpanHolder getNewInstance(CharacterStyle[] spans, int start, int end, int spaces){
return new SpanHolder(spans,start,end,spaces);
}
public boolean isTextChunkPadded() {
return textChunkPadded;
}
public void setTextChunkPadded(boolean textChunkPadded) {
this.textChunkPadded = textChunkPadded;
}
public int getWordHolderIndex() {
return wordHolderIndex;
}
public void setWordHolderIndex(int wordHolderIndex) {
this.wordHolderIndex = wordHolderIndex;
}
public CharacterStyle[] getSpans() {
return spans;
}
public void setSpans(CharacterStyle[] spans) {
this.spans = spans;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public int getCurrentSpaces() {
return currentSpaces;
}
public void setCurrentSpaces(int currentSpaces) {
this.currentSpaces = currentSpaces;
}
}
GOOD LUCK! (Y)

Dynamic playlists with Exoplayer 2

I'd like to use ExoPlayer2 with playlists having possibility to dinamically change the tracks (add or remove them from playlist) and change the loop settings.
Since ConcatenatingMediaSource has static arrays (and not lists), I'm implementing a DynamicMediaSource, like Concatenating one but with lists instead of arrays and one mode method addSource to add one more media source to the list.
public void addSource(MediaSource mediaSource) {
this.mediaSources.add(mediaSource);
duplicateFlags = buildDuplicateFlags(this.mediaSources);
if(!mediaSources.isEmpty())
prepareSource(mediaSources.size() -1);
else
prepareSource(0);
}
When I invoke addSource
MediaSource ms = buildMediaSource(mynewuri, null);
mediaSource.addSource(ms);
the track is added to the arrays but it seems something is missing because I always obtain ArrayOutOfBoundsException in createPeriod method.
In createPeriod the method
mediaSources.get(sourceIndex)...
is trying to access the index = mediaSources.size().
Can you help me?
I eventually managed it.
It was my fault during the conversion from arrays to lists.
I had to use SparseArrays for timelines and manifests and everything began to work.
In the DynamicMediaSource simply set the following types:
private final List<MediaSource> mediaSources;
private final SparseArray<Timeline> timelines;
private final SparseArray<Object> manifests;
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod;
private SparseArray<Boolean> duplicateFlags;
you have to use sparse arrays to set the proper values into the timelines and manifests in the method
private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline,
Object sourceManifest) {
// Set the timeline and manifest.
timelines.put(sourceFirstIndex, sourceTimeline);
manifests.put(sourceFirstIndex, sourceManifest);
// Also set the timeline and manifest for any duplicate entries of the same source.
for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) {
if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) {
timelines.put(i, sourceTimeline);
manifests.put(i, sourceManifest);
}
}
for(int i= 0; i<mediaSources.size(); i++){
if(timelines.get(i) == null){
// Don't invoke the listener until all sources have timelines.
return;
}
}
timeline = new DynamicTimeline(new ArrayList(asList(timelines)));
listener.onSourceInfoRefreshed(timeline, new ArrayList(asList(manifests)));
}
Here is the complete code of DynamicMediaSource class:
public final class DynamicMediaSource implements MediaSource {
private static final String TAG = "DynamicSource";
private final List<MediaSource> mediaSources;
private final List<Timeline> timelines;
private final List<Object> manifests;
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod;
private SparseArray<Boolean> duplicateFlags;
private Listener listener;
private DynamicTimeline timeline;
/**
* #param mediaSources The {#link MediaSource}s to concatenate. It is valid for the same
* {#link MediaSource} instance to be present more than once in the array.
*/
public DynamicMediaSource(MediaSource... mediaSources) {
this.mediaSources = new ArrayList<MediaSource>(Arrays.asList(mediaSources));
timelines = new ArrayList<Timeline>();
manifests = new ArrayList<Object>();
sourceIndexByMediaPeriod = new HashMap<>();
duplicateFlags = buildDuplicateFlags(this.mediaSources);
}
public void addSource(MediaSource mediaSource) {
this.mediaSources.add(mediaSource);
duplicateFlags = buildDuplicateFlags(this.mediaSources);
/*if(!mediaSources.isEmpty())
prepareSource(mediaSources.size() -1);
else
prepareSource(0);*/
}
#Override
public void prepareSource(Listener listener) {
this.listener = listener;
for (int i = 0; i < mediaSources.size(); i++) {
prepareSource(i);
/*if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
final int index = i;
mediaSources.get(i).prepareSource(new Listener() {
#Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
handleSourceInfoRefreshed(index, timeline, manifest);
}
});
}*/
}
}
private void prepareSource(int sourceindex) {
if (duplicateFlags.get(sourceindex) == null || !duplicateFlags.get(sourceindex)) {
final int index = sourceindex;
mediaSources.get(sourceindex).prepareSource(new Listener() {
#Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
handleSourceInfoRefreshed(index, timeline, manifest);
}
});
}
}
#Override
public void maybeThrowSourceInfoRefreshError() throws IOException {
for (int i = 0; i < mediaSources.size(); i++) {
if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
mediaSources.get(i).maybeThrowSourceInfoRefreshError();
}
}
}
#Override
public MediaPeriod createPeriod(int index, Callback callback, Allocator allocator,
long positionUs) {
int sourceIndex = timeline.getSourceIndexForPeriod(index);
int periodIndexInSource = index - timeline.getFirstPeriodIndexInSource(sourceIndex);
MediaPeriod mediaPeriod = mediaSources.get(sourceIndex).createPeriod(periodIndexInSource, callback,
allocator, positionUs);
sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex);
return mediaPeriod;
}
#Override
public void releasePeriod(MediaPeriod mediaPeriod) {
int sourceIndex = sourceIndexByMediaPeriod.get(mediaPeriod);
sourceIndexByMediaPeriod.remove(mediaPeriod);
mediaSources.get(sourceIndex).releasePeriod(mediaPeriod);
}
#Override
public void releaseSource() {
for (int i = 0; i < mediaSources.size(); i++) {
if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
mediaSources.get(i).releaseSource();
}
}
}
private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline,
Object sourceManifest) {
// Set the timeline and manifest.
timelines.add(sourceFirstIndex, sourceTimeline);
manifests.add(sourceFirstIndex, sourceManifest);
// Also set the timeline and manifest for any duplicate entries of the same source.
for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) {
if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) {
timelines.add(i, sourceTimeline);
manifests.add(i, sourceManifest);
}
}
for (Timeline timeline : timelines) {
if (timeline == null) {
// Don't invoke the listener until all sources have timelines.
return;
}
}
timeline = new DynamicTimeline(new ArrayList(timelines));
listener.onSourceInfoRefreshed(timeline, new ArrayList(manifests));
}
private static SparseArray<Boolean> buildDuplicateFlags(List<MediaSource> mediaSources) {
SparseArray<Boolean> duplicateFlags = new SparseArray<Boolean>();
IdentityHashMap<MediaSource, Void> sources = new IdentityHashMap<>(mediaSources.size());
for (int i = 0; i < mediaSources.size(); i++) {
MediaSource mediaSource = mediaSources.get(i);
if (!sources.containsKey(mediaSource)) {
sources.put(mediaSource, null);
} else {
duplicateFlags.setValueAt(i, true);
}
}
return duplicateFlags;
}
/**
* A {#link Timeline} that is the concatenation of one or more {#link Timeline}s.
*/
private static final class DynamicTimeline extends Timeline {
private final List<Timeline> timelines;
private final List<Integer> sourcePeriodOffsets;
private final List<Integer> sourceWindowOffsets;
public DynamicTimeline(List<Timeline> timelines) {
List<Integer> sourcePeriodOffsets = new ArrayList<>();
List<Integer> sourceWindowOffsets = new ArrayList<>();
int periodCount = 0;
int windowCount = 0;
for (Timeline timeline : timelines) {
periodCount += timeline.getPeriodCount();
windowCount += timeline.getWindowCount();
sourcePeriodOffsets.add(periodCount);
sourceWindowOffsets.add(windowCount);
}
this.timelines = timelines;
this.sourcePeriodOffsets = sourcePeriodOffsets;
this.sourceWindowOffsets = sourceWindowOffsets;
}
#Override
public int getWindowCount() {
return sourceWindowOffsets.get(sourceWindowOffsets.size() - 1);
}
#Override
public Window getWindow(int windowIndex, Window window, boolean setIds) {
int sourceIndex = getSourceIndexForWindow(windowIndex);
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
timelines.get(sourceIndex).getWindow(windowIndex - firstWindowIndexInSource, window, setIds);
window.firstPeriodIndex += firstPeriodIndexInSource;
window.lastPeriodIndex += firstPeriodIndexInSource;
return window;
}
#Override
public int getPeriodCount() {
return sourcePeriodOffsets.get(sourcePeriodOffsets.size() - 1);
}
#Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
int sourceIndex = getSourceIndexForPeriod(periodIndex);
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
timelines.get(sourceIndex).getPeriod(periodIndex - firstPeriodIndexInSource, period, setIds);
period.windowIndex += firstWindowIndexInSource;
if (setIds) {
period.uid = Pair.create(sourceIndex, period.uid);
}
return period;
}
#Override
public int getIndexOfPeriod(Object uid) {
if (!(uid instanceof Pair)) {
return C.INDEX_UNSET;
}
Pair<?, ?> sourceIndexAndPeriodId = (Pair<?, ?>) uid;
if (!(sourceIndexAndPeriodId.first instanceof Integer)) {
return C.INDEX_UNSET;
}
int sourceIndex = (Integer) sourceIndexAndPeriodId.first;
Object periodId = sourceIndexAndPeriodId.second;
if (sourceIndex < 0 || sourceIndex >= timelines.size()) {
return C.INDEX_UNSET;
}
int periodIndexInSource = timelines.get(sourceIndex).getIndexOfPeriod(periodId);
return periodIndexInSource == C.INDEX_UNSET ? C.INDEX_UNSET
: getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource;
}
private int getSourceIndexForPeriod(int periodIndex) {
return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1;
}
private int getFirstPeriodIndexInSource(int sourceIndex) {
return sourceIndex == 0 ? 0 : sourcePeriodOffsets.get(sourceIndex - 1);
}
private int getSourceIndexForWindow(int windowIndex) {
return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
}
private int getFirstWindowIndexInSource(int sourceIndex) {
return sourceIndex == 0 ? 0 : sourceWindowOffsets.get(sourceIndex - 1);
}
}
}

android , How could I make this code short using For loop

this is my code
LinearLayout ll[] = new LinearLayout [9];
ll[0]=(LinearLayout)findViewById(R.id.rlay1);
ll[1]=(LinearLayout)findViewById(R.id.rlay2);
ll[2]=(LinearLayout)findViewById(R.id.rlay3);
ll[3]=(LinearLayout)findViewById(R.id.rlay4);
ll[4]=(LinearLayout)findViewById(R.id.rlay5);
ll[5]=(LinearLayout)findViewById(R.id.rlay6);
ll[6]=(LinearLayout)findViewById(R.id.rlay7);
ll[7]=(LinearLayout)findViewById(R.id.rlay8);
ll[8]=(LinearLayout)findViewById(R.id.rlay9);
ll[9]=(LinearLayout)findViewById(R.id.rlay10);
You could put the ids into an array:
int[] ids = new int[] {R.id.rlay1, R.id.rlay2, R.id.rlay3, R.id.rlay4, R.id.rlay5,
R.id.rlay6, R.id.rlay7, R.id.rlay8, R.id.rlay9, R.id.rlay10};
LinearLayout ll[] = new LinearLayout [10];
for (int i = 0; i < 10; i++) {
ll[i] = (LinearLayout)findViewById(ids[i]);
}
I prefer this solution over the use of Resources.getIdentifier since it does not cause resource id lookup costs at runtime.
LinearLayout ll[] = new LinearLayout [10];
int counter = 0;
for (int i = 1; i < 11; i++) {
int id = getResources().getIdentifier("rlay"+i, "id", getPackageName());
ll[counter++] = (LinearLayout)findViewById(id);
}
Add this method to your code:
protected final static int getResourceID
(final String resName, final String resType, final Context ctx)
{
final int ResourceID =
ctx.getResources().getIdentifier(resName, resType,
ctx.getApplicationInfo().packageName);
if (ResourceID == 0)
{
throw new IllegalArgumentException
(
"No resource string found with name " + resName
);
}
else
{
return ResourceID;
}
}
Then change your code so:
LinearLayout ll[] = new LinearLayout [10];
Context ctx = getApplicationContext();
for (int i = 0; i < 10; i++)
{
ll[i] = (LinearLayout) findViewById(getResourceID("rlay" + (i + 1), "id", ctx));
}

Android: If/Else statement makes app crash

I'm trying to tell if an android int is null by using If/Else
public void onClick(View v) {
EditText min = (EditText) findViewById(R.id.EditText01);
EditText max = (EditText) findViewById(R.id.maxnum);
EditText res = (EditText) findViewById(R.id.res);
int myMin = Integer.parseInt(min.getText().toString());
int myMax = Integer.parseInt(max.getText().toString());
String minString = String.valueOf(myMin);
String maxString = String.valueOf(myMax);
int f = (int) ((Math.random()*(myMax-myMin+1))+myMin);
if (minString.equals(""))
{
// Do Nothing
}
if (maxString.equals(""))
{
// Do Nothing
}
res.setText(String.valueOf(f));
There are no any errors, but when I'm running the app its crashing when im pressing the button.
I'm also trying to use null instead of "":
if (minString.equals(null))
{
// Do Nothing
}
if (maxString.equals(null))
{
// Do Nothing
}
And i have a crash.
Please help me!!!
public boolean equals (Object object)
Compares the specified object to this string and returns true if they are equal. The object must be an instance of string with the same characters in the same order.
So its returning error so if you want to check if its null then use == operator on the object.
if (maxString == null )
Use
int myMin = 0;
int myMax = 0;
if(min.getText().toString()!="")
myMin = Integer.parseInt(min.getText().toString());
if(max.getText().toString()!="")
myMax = Integer.parseInt(max.getText().toString());
String minString = String.valueOf(myMin);
String maxString = String.valueOf(myMax);
int f = (int) ((Math.random()*(myMax-myMin+1))+myMin);
if (minString.equals(""))
{
// Do Nothing
}
if (maxString.equals(""))
{
// Do Nothing
}
do if (maxString == null )
{
// do something
}
int variables can't be null
If a null is to be converted to int, then it is the converter which decides whether to set 0, throw exception, or set another value (like Integer.MIN_VALUE)
So if you convert int to string again you cannot get null value.
check = input.getText().toString();
try {
if (!check.equals("null")) {
int max = Integer.parseInt(input.getText().toString());
int constant1 = 1;
int constant2 = 1;
int nextNumber = 0;
int count = 0;
String fibResult = "";
for (int i = 0; i <= max; i++) {
fibResult += "F" + count + "=" + nextNumber + "\n";
constant1 = constant2;
constant2 = nextNumber;
nextNumber = constant1 + constant2;
count++;
}
dspResults.setText("\n" + fibResult);
} else {
dspResults.setVisibility(View.VISIBLE);
dspResults.setText("Invalid");
dspResults.setText(Gravity.CENTER);
dspResults.setTextColor(Color.DKGRAY);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
public void onClick(View v) {
EditText min = (EditText) findViewById(R.id.EditText01);
EditText max = (EditText) findViewById(R.id.maxnum);
EditText res = (EditText) findViewById(R.id.res);
int myMin = Integer.parseInt(min.getText().toString());
int myMax = Integer.parseInt(max.getText().toString());
String minString = String.valueOf(myMin);
String maxString = String.valueOf(myMax);
int f = (int) ((Math.random()*(myMax-myMin+1))+myMin);
{
if (minString.equals(""))
{
// Do Nothing
res.setText(String.valueOf(f));
return false;
}
else if (maxString.equals(""))
{
// Do Nothing
res.setText(String.valueOf(f));
return false;
}
else
res.setText(String.valueOf(f));
return true ;
}

Categories

Resources