Android Open Source - holoaccent Accent Resources






From Project

Back to project page holoaccent.

License

The source code is released under:

Apache License

If you think the Android project holoaccent listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright 2013 NEGU Soft/*from   w w  w .  j a v a2  s . c o m*/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package com.negusoft.holoaccent;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.TypedValue;

import com.negusoft.holoaccent.interceptor.AccentColorInterceptor;
import com.negusoft.holoaccent.interceptor.ActionBarBackgroundInterceptor;
import com.negusoft.holoaccent.interceptor.CircleInterceptor;
import com.negusoft.holoaccent.interceptor.ContactBadgeInterceptor;
import com.negusoft.holoaccent.interceptor.FastScrollInterceptor;
import com.negusoft.holoaccent.interceptor.IndeterminateInterceptor;
import com.negusoft.holoaccent.interceptor.NativeInterceptor;
import com.negusoft.holoaccent.interceptor.PagerTabStripInterceptor;
import com.negusoft.holoaccent.interceptor.RectInterceptor;
import com.negusoft.holoaccent.interceptor.RoundRectInterceptor;
import com.negusoft.holoaccent.interceptor.ScrubberInterceptor;
import com.negusoft.holoaccent.interceptor.SearchViewTextFieldInterceptor;
import com.negusoft.holoaccent.interceptor.SolidColorInterceptor;
import com.negusoft.holoaccent.interceptor.SpinnerInterceptor;
import com.negusoft.holoaccent.interceptor.ToggleInterceptor;
import com.negusoft.holoaccent.interceptor.UnderlineInterceptor;
import com.negusoft.holoaccent.util.BitmapUtils;
import com.negusoft.holoaccent.util.NativeResources;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Extends the default android Resources to replace and modify 
 * drawables at runtime and apply the accent color.
 * <br/><br/>
 * "openRawResource()" and "getDrawable()" are called when inflating 
 * XML drawable resources. By overriding them, we can replace the 
 * components that form the drawables at runtime.
 * <br/><br/>
 * For the OverScroll, the native android drawables are modified 
 * directly. We look up their id by name, and then we replace the 
 * drawable with a tinted version by applying a ColorFilter.
 */
public class AccentResources extends Resources {
  
  public interface Interceptor {
    /** @return The drawable to be replaced or null to continue the normal flow. */
    public Drawable getDrawable(Resources res, AccentPalette palette, int resId);
  }

    public interface ColorInterceptor {
        /** @return The color to be replaced or 0 to continue the normal flow. */
        public int getColor(Resources res, AccentPalette palette, int resId);
    }
  
  private static final int[] TINT_DRAWABLE_IDS = new int[] {
    R.drawable.ha__textfield_comp_activated_left,
    R.drawable.ha__textfield_comp_activated_main,
    R.drawable.ha__textfield_comp_activated_right,
    R.drawable.ha__textfield_comp_focused_left,
    R.drawable.ha__textfield_comp_focused_main,
    R.drawable.ha__textfield_comp_focused_right,
    R.drawable.ha__btn_check_comp_off_focus,
    R.drawable.ha__btn_check_comp_on_focus,
    R.drawable.ha__progress_comp_primary
  };
  
  private static final int[] TINT_TRANSFORMATION_DRAWABLE_IDS = new int[] {
    R.drawable.ha__text_select_handle_middle_transformation,
    R.drawable.ha__text_select_handle_left_transformation,
    R.drawable.ha__text_select_handle_right_transformation,
    R.drawable.ha__btn_check_on_transformation,
    R.drawable.ha__btn_check_on_transformation_light,
    R.drawable.ha__btn_radio_comp_dot_transformation
  };

  private final Context mContext;
  private final int mExplicitColor;
    private final int mExplicitColorDark;
    private final int mExplicitColorActionBar;

    private final List<Interceptor> mInterceptors = new ArrayList<Interceptor>();
    private final List<ColorInterceptor> mColorInterceptors = new ArrayList<ColorInterceptor>();

    private List<Integer> mCustomTintDrawableIds;
    private List<Integer> mCustomTransformationDrawableIds;
    private int[] mTintDrawableIds;
    private int[] mTransformationDrawableIds;
  
  private boolean mInitialized = false;
    private boolean mInitializingFlag = false;
  private AccentPalette mPalette;
  
  public AccentResources(Context c, Resources resources) {
    super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
    mContext = c;
    mExplicitColor = 0;
    mExplicitColorDark = 0;
        mExplicitColorActionBar = 0;
  }
  
  public AccentResources(Context c, Resources resources, int color) {
    super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
    mContext = c;
    mExplicitColor = color;
    mExplicitColorDark = 0;
        mExplicitColorActionBar = 0;
  }
  
  public AccentResources(Context c, Resources resources, int color, int colorDark, int colorActionBar) {
    super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
    mContext = c;
    mExplicitColor = color;
    mExplicitColorDark = colorDark;
        mExplicitColorActionBar = colorActionBar;
  }
  
  /**
   * Make sure that the instance is initialized. It will check the 'mInitialized' 
   * flag even if it is done within 'initialize()', to avoid getting into the 
   * synchronized block every time.
     * @return True if we are initializing. This means that initialize has been called recursively,
     * in which case a default value must be returned to avoid a "stack overflow".
   */
  private boolean checkInitialized() {
    if (mInitialized)
      return false;
    return initialize(mContext, mExplicitColor, mExplicitColorDark, mExplicitColorActionBar);
  }

  private synchronized boolean initialize(Context c, int explicitColor, int explicitColorDark, int explicitColorActionBar) {
    if (mInitialized)
      return false;
        if (mInitializingFlag)
            return true;

        mInitializingFlag = true;
    mPalette = initPalette(c, explicitColor, explicitColorDark, explicitColorActionBar);
        mTintDrawableIds = appendDrawableIds(TINT_DRAWABLE_IDS, mCustomTintDrawableIds);
        mTransformationDrawableIds = appendDrawableIds(TINT_TRANSFORMATION_DRAWABLE_IDS, mCustomTransformationDrawableIds);
    addInterceptors(c);
        mInitializingFlag = false;
    mInitialized = true;

        return false;
  }

    private int[] appendDrawableIds(int[] defaults, List<Integer> custom) {
        if (custom == null)
            return defaults;

        int customSize = custom.size();
        int[] result = new int[defaults.length + customSize];
        for (int i=0; i<customSize; i++)
            result[i] = custom.get(i);
        for (int i=0; i<defaults.length; i++)
            result[customSize + i] = defaults[i];

        return result;
    }
  
  private AccentPalette initPalette(Context c, int explicitColor, int explicitColorDark, int explicitColorActionBar) {
    TypedArray attrs = c.getTheme().obtainStyledAttributes(R.styleable.HoloAccent);

        int holoBlue = super.getColor(android.R.color.holo_blue_light);
    int color = explicitColor != 0 ? explicitColor : 
      attrs.getColor(R.styleable.HoloAccent_accentColor, holoBlue);
    int colorDark = explicitColorDark != 0 ? explicitColorDark : 
      attrs.getColor(R.styleable.HoloAccent_accentColorDark, 0);
        int colorActionBar = explicitColorActionBar != 0 ? explicitColorActionBar :
                attrs.getColor(R.styleable.HoloAccent_accentColorActionBar, color);

        attrs.recycle();
    
    return new AccentPalette(color, colorDark, colorActionBar);
  }
  
  private void addInterceptors(Context c) {
    mInterceptors.add(new ToggleInterceptor());
    mInterceptors.add(new UnderlineInterceptor());
    mInterceptors.add(new SolidColorInterceptor());
    mInterceptors.add(new RectInterceptor());
    mInterceptors.add(new RoundRectInterceptor());
    mInterceptors.add(new CircleInterceptor());
    mInterceptors.add(new ScrubberInterceptor());
    mInterceptors.add(new FastScrollInterceptor());
    mInterceptors.add(new IndeterminateInterceptor());
    mInterceptors.add(new SpinnerInterceptor());
    mInterceptors.add(new SearchViewTextFieldInterceptor());
        mInterceptors.add(new NativeInterceptor());
        mInterceptors.add(new ActionBarBackgroundInterceptor(mContext));
        mInterceptors.add(new PagerTabStripInterceptor());
        mInterceptors.add(new ContactBadgeInterceptor());
        mInterceptors.add(new OverScrollInterceptor());

        mColorInterceptors.add(new AccentColorInterceptor());
  }

    @Override
    public int getColor(int resId) throws NotFoundException {
        if (checkInitialized())
            return super.getColor(resId);

        // Give a chance to the interceptors to replace the drawable
        int result;
        for(ColorInterceptor interceptor : mColorInterceptors) {
            result = interceptor.getColor(this, mPalette, resId);
            if (result != 0)
                return result;
        }

        return super.getColor(resId);
    }


    @Override
    public Drawable getDrawable(int resId) throws Resources.NotFoundException {
        if (checkInitialized())
            return super.getDrawable(resId);

        // Give a chance to the interceptors to replace the drawable
        Drawable result;
        for(Interceptor interceptor : mInterceptors) {
            result = interceptor.getDrawable(this, mPalette, resId);
            if (result != null)
                return result;
        }

        return super.getDrawable(resId);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
    @Override
    public Drawable getDrawableForDensity(int resId, int density) throws NotFoundException {
        if (checkInitialized())
            return super.getDrawableForDensity(resId, density);

        // Give a chance to the interceptors to replace the drawable
        Drawable result;
        for(Interceptor interceptor : mInterceptors) {
            result = interceptor.getDrawable(this, mPalette, resId);
            if (result != null)
                return result;
        }

        return super.getDrawableForDensity(resId, density);
    }

    @TargetApi(Build.VERSION_CODES.L)
    @Override
    public Drawable getDrawable(int resId, Theme theme) throws NotFoundException {
        if (checkInitialized())
            return super.getDrawable(resId, theme);

        // Give a chance to the interceptors to replace the drawable
        Drawable result;
        for(Interceptor interceptor : mInterceptors) {
            result = interceptor.getDrawable(this, mPalette, resId);
            if (result != null)
                return result;
        }
        return super.getDrawable(resId, theme);
    }

    @TargetApi(Build.VERSION_CODES.L)
    @Override
    public Drawable getDrawableForDensity(int resId, int density, Theme theme) {
        if (checkInitialized())
            return super.getDrawableForDensity(resId, density, theme);

        // Give a chance to the interceptors to replace the drawable
        Drawable result;
        for(Interceptor interceptor : mInterceptors) {
            result = interceptor.getDrawable(this, mPalette, resId);
            if (result != null)
                return result;
        }
        return super.getDrawableForDensity(resId, density, theme);
    }
  
  @Override
  public InputStream openRawResource(int resId, TypedValue value)
      throws NotFoundException {
        if (checkInitialized())
            return super.openRawResource(resId, value);
    
    for (int id : mTintDrawableIds) {
      if (resId == id)
        return getTintendResourceStream(resId, value, mPalette.accentColor);
    }
    for (int id : mTransformationDrawableIds) {
      if (resId == id)
        return getTintTransformationResourceStream(resId, value, mPalette.accentColor);
    }
    return super.openRawResource(resId, value);
  }

    /**
     * Method to access the palette instance
     */
    public AccentPalette getPalette() {
        if (checkInitialized())
            throw new RuntimeException("HoloAccent: Unexpected initialization exception in initialization.");
        return mPalette;
    }

    /**
     * Add a drawable interceptor. They are evaluated in the order they are added, and before the
     * default interceptors.
     */
    public void addInterceptor(Interceptor interceptor) {
        mInterceptors.add(0, interceptor);
    }

    /**
     * Add a color interceptor. They are evaluated in the order they are added, and before the
     * default interceptors.
     */
    public void addColorInterceptor(ColorInterceptor interceptor) {
        mColorInterceptors.add(0, interceptor);
    }

    /** Add a drawable resource to which to apply the "tint" technique. */
    public void addTintResourceId(int resId) {
        if (mCustomTintDrawableIds == null)
            mCustomTintDrawableIds = new ArrayList<Integer>();
        mCustomTintDrawableIds.add(resId);
    }

    /** Add a drawable resource to which to apply the "tint transformation" technique. */
    public void addTintTransformationResourceId(int resId) {
        if (mCustomTransformationDrawableIds == null)
            mCustomTransformationDrawableIds = new ArrayList<Integer>();
        mCustomTransformationDrawableIds.add(resId);
    }
  
  /**
   * Get a reference to a resource that is equivalent to the one requested, 
   * but with the accent color applied to it.
   */
  private InputStream getTintendResourceStream(int id, TypedValue value, int color) {
    Bitmap bitmap = getBitmapFromResource(id, value);
    bitmap = BitmapUtils.applyColor(bitmap, color);
    return getStreamFromBitmap(bitmap);
  }
  
  /**
   * Get a reference to a resource that is equivalent to the one requested, 
   * but changing the tint from the original red to the given color.
   */
  private InputStream getTintTransformationResourceStream(int id, TypedValue value, int color) {
    Bitmap bitmap = getBitmapFromResource(id, value);
    bitmap = BitmapUtils.processTintTransformationMap(bitmap, color);
    return getStreamFromBitmap(bitmap);
  }
  
  private Bitmap getBitmapFromResource(int resId, TypedValue value) {
    InputStream original = super.openRawResource(resId, value);
    value.density = getDisplayMetrics().densityDpi;
    final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inDither = false;
        options.inScaled = false;
        options.inScreenDensity = getDisplayMetrics().densityDpi;
    return BitmapFactory.decodeResourceStream(
        this, value, original, 
        new Rect(), options);
  }
  
  private InputStream getStreamFromBitmap(Bitmap bitmap) {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bitmap.compress(CompressFormat.PNG, 100 /*ignored for PNG*/, bos);
    byte[] bitmapData = bos.toByteArray();
    try {
      bos.close();
    } catch (IOException e) { /* ignore */}
    
    return new ByteArrayInputStream(bitmapData);
  }
  
  /**
   * Inner class holding the logic for applying a ColorFilter to the OverScroll 
   * drawables. It is implemented a an inner class because it needs to access 
   * the parents implementation of getDrawable().
   */
  private class OverScrollInterceptor implements Interceptor {

    private static final String RESOURCE_NAME_EDGE = "overscroll_edge";
    private static final String RESOURCE_NAME_GLOW = "overscroll_glow";

    private final int mOverscrollEdgeId;
    private final int mOverscrollGlowId;

        private Drawable mOverscrollEdgeDrawable;
        private Drawable mOverscrollGlowDrawable;
    
    public OverScrollInterceptor() {
            mOverscrollEdgeId = NativeResources.getDrawableIdentifier(RESOURCE_NAME_EDGE);
            mOverscrollGlowId = NativeResources.getDrawableIdentifier(RESOURCE_NAME_GLOW);
    }

    @Override
    public Drawable getDrawable(Resources res, AccentPalette palette, int resId) {
      if (resId == mOverscrollEdgeId)
        return getEdgeDrawable();
      if (resId == mOverscrollGlowId)
        return getGlowDrawable();
      return null;
    }
    
    private Drawable getEdgeDrawable() {
            if (mOverscrollEdgeDrawable == null) {
                mOverscrollEdgeDrawable = AccentResources.super.getDrawable(R.drawable.ha__overscroll_edge);
                mOverscrollEdgeDrawable.setColorFilter(mPalette.accentColor, PorterDuff.Mode.MULTIPLY);
            }
      return mOverscrollEdgeDrawable;
    }
    
    private Drawable getGlowDrawable() {
            if (mOverscrollGlowDrawable == null) {
                mOverscrollGlowDrawable = AccentResources.super.getDrawable(R.drawable.ha__overscroll_glow);
                mOverscrollGlowDrawable.setColorFilter(mPalette.accentColor, PorterDuff.Mode.MULTIPLY);
            }
      return mOverscrollGlowDrawable;
    }
  }

}




Java Source Code List

com.negusoft.holoaccent.AccentHelper.java
com.negusoft.holoaccent.AccentPalette.java
com.negusoft.holoaccent.AccentResources.java
com.negusoft.holoaccent.activity.AccentActivity.java
com.negusoft.holoaccent.dialog.AccentAlertDialog.java
com.negusoft.holoaccent.dialog.AccentDatePickerDialog.java
com.negusoft.holoaccent.dialog.AccentDialogFragment.java
com.negusoft.holoaccent.dialog.AccentTimePickerDialog.java
com.negusoft.holoaccent.dialog.DividerPainter.java
com.negusoft.holoaccent.dialog.NumberPickerPainter.java
com.negusoft.holoaccent.drawable.ActionBarBackgroundDrawable.java
com.negusoft.holoaccent.drawable.CircleDrawable.java
com.negusoft.holoaccent.drawable.ContactBadgeDrawable.java
com.negusoft.holoaccent.drawable.FastScrollDrawable.java
com.negusoft.holoaccent.drawable.IndeterminedProgressDrawable.java
com.negusoft.holoaccent.drawable.IndeterminedProgressLegacyDrawable.java
com.negusoft.holoaccent.drawable.RectDrawable.java
com.negusoft.holoaccent.drawable.RoundRectDrawable.java
com.negusoft.holoaccent.drawable.ScrubberControlSelectorDrawable.java
com.negusoft.holoaccent.drawable.ScrubberProgressDrawable.java
com.negusoft.holoaccent.drawable.SearchViewDrawable.java
com.negusoft.holoaccent.drawable.SpinnerDrawable.java
com.negusoft.holoaccent.drawable.ToggleForegroundDrawable.java
com.negusoft.holoaccent.drawable.UnderlineDrawable.java
com.negusoft.holoaccent.example.activity.AccentFragmentActivity.java
com.negusoft.holoaccent.example.activity.DialogActivity.java
com.negusoft.holoaccent.example.activity.MainActivity.java
com.negusoft.holoaccent.example.activity.PreferencesActivity.java
com.negusoft.holoaccent.example.activity.SpinnerActivity.java
com.negusoft.holoaccent.example.activity.TabbedActivity.java
com.negusoft.holoaccent.example.activity.TabbedStripActivity.java
com.negusoft.holoaccent.example.activity.themed.DialogActivityLight.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityColoredAB.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityLightColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityLightColoredAB.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityLightDarkAB.java
com.negusoft.holoaccent.example.activity.themed.PreferencesActivityLight.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityColoredAB.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityLightColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityLightColoredAB.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityLightDarkAB.java
com.negusoft.holoaccent.example.activity.themed.SpinnerActivityLight.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityColoredAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityLightColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityLightColoredAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityLightDarkAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedActivityLight.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityColoredAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityLightColoredABInverse.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityLightColoredAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityLightDarkAB.java
com.negusoft.holoaccent.example.activity.themed.TabbedStripActivityLight.java
com.negusoft.holoaccent.example.fragment.AccentSupportDialogFragment.java
com.negusoft.holoaccent.example.fragment.ButtonFragment.java
com.negusoft.holoaccent.example.fragment.ChoicesFragment.java
com.negusoft.holoaccent.example.fragment.ListFragment.java
com.negusoft.holoaccent.example.fragment.PickersFragment.java
com.negusoft.holoaccent.example.fragment.ProgressFragment.java
com.negusoft.holoaccent.example.fragment.SimpleDialogFragment.java
com.negusoft.holoaccent.example.fragment.TextviewFragment.java
com.negusoft.holoaccent.example.model.ColorOverrideConfig.java
com.negusoft.holoaccent.example.preference.CustomDialogPreference.java
com.negusoft.holoaccent.example.view.CheckableTextView.java
com.negusoft.holoaccent.interceptor.AccentColorInterceptor.java
com.negusoft.holoaccent.interceptor.ActionBarBackgroundInterceptor.java
com.negusoft.holoaccent.interceptor.CircleInterceptor.java
com.negusoft.holoaccent.interceptor.ContactBadgeInterceptor.java
com.negusoft.holoaccent.interceptor.FastScrollInterceptor.java
com.negusoft.holoaccent.interceptor.IndeterminateInterceptor.java
com.negusoft.holoaccent.interceptor.NativeInterceptor.java
com.negusoft.holoaccent.interceptor.PagerTabStripInterceptor.java
com.negusoft.holoaccent.interceptor.RectInterceptor.java
com.negusoft.holoaccent.interceptor.RoundRectInterceptor.java
com.negusoft.holoaccent.interceptor.ScrubberInterceptor.java
com.negusoft.holoaccent.interceptor.SearchViewTextFieldInterceptor.java
com.negusoft.holoaccent.interceptor.SolidColorInterceptor.java
com.negusoft.holoaccent.interceptor.SpinnerInterceptor.java
com.negusoft.holoaccent.interceptor.ToggleInterceptor.java
com.negusoft.holoaccent.interceptor.UnderlineInterceptor.java
com.negusoft.holoaccent.preference.DialogPreference.java
com.negusoft.holoaccent.preference.EditTextPreference.java
com.negusoft.holoaccent.preference.ListPreference.java
com.negusoft.holoaccent.preference.MultiSelectListPreference.java
com.negusoft.holoaccent.preference.SwitchPreference.java
com.negusoft.holoaccent.util.BitmapUtils.java
com.negusoft.holoaccent.util.NativeResources.java
com.negusoft.holoaccent.widget.AccentDatePicker.java
com.negusoft.holoaccent.widget.AccentNumberPicker.java
com.negusoft.holoaccent.widget.AccentQuickContactBadge.java
com.negusoft.holoaccent.widget.AccentRatingBar.java
com.negusoft.holoaccent.widget.AccentSearchView.java
com.negusoft.holoaccent.widget.AccentSwitch.java
com.negusoft.holoaccent.widget.AccentTimePicker.java