使用android sdk 隐藏的类--VolumePreference

 

Android真是可恶 ,sdk里面有的类但是在使用的时候却被隐藏了 ……真不知道他为啥要在sdk里面公开出来,
 
你都用不了,你公开有啥用阿……网上找了一下解决办法 ,一种是说通过定制定制android.jar的方法来实现
(传送门:http://luhuajcdd.iteye.com/blog/1242419   ),另一种是说使用反射的办法。但是第一种在

 

用混淆的时候出错了,依然提示该类无法找到。没办法只好使用反射拉,不过如果需要继承这个隐藏的类那又

 

改咋办呢?ok,那就是下载源代码,然后从将 android.preference.VolumePreference 源代码移到我们的项目

 

中去吧,酱紫就可以解决了。 

 

不过导入到项目中也不是意见很简单的事情,要知道他还会引用其他的类呢,搞不好。。。要导入一堆类呢。

 

下面就是已经完成了的  android.preference.VolumePreference 的类,我已经将其改名成 VolumePreferenceEx

 

这样,引用就不会有歧义拉。。

 

 

 

ExpandedBlockStart.gif View Code 
package apollo.preference;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.preference.Preference.BaseSavedState;
import android.preference.PreferenceManager.OnActivityStopListener;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import apollo.profilesetting.view.R;

public  class VolumePreferenceEx  extends SeekBarPreferenceEx  implements
        PreferenceManager.OnActivityStopListener, View.OnKeyListener {

     private  int mStreamType;
     private SeekBarVolumizer mSeekBarVolumizer;
    
     public VolumePreferenceEx(Context context, AttributeSet attrs) {
         super(context, attrs);
        Class<?> clazz =  null;
         int[] styleable =  null;
        Field field =  null;
         int stream_type = 0;
        
         try {
            clazz = Class.forName("android.R$styleable");
            field = clazz.getField("VolumePreference");  
            styleable = ( int[])field.get(clazz);
            
            field = clazz.getField("VolumePreference");  
            stream_type = (Integer)field.get(clazz);
        }  catch (Exception ex) {
            styleable =  new  int[]{16843273};
        }

         //  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VolumePreference, 0, 0);
        
//  mStreamType = a.getInt(R.styleable.VolumePreference_streamType, 0);
        
//  a.recycle();

        
// int[] styleable = {16843273};
        
        
        TypedArray a = context.obtainStyledAttributes(attrs, styleable, 0, 0);
        mStreamType = a.getInt(stream_type, 0);
        a.recycle();
    }
    
     public  void setStreamType( int streamType) {
        mStreamType = streamType;
    }
    
     private  void callActivityStopListener(String name) {
        Method method =  null;
        PreferenceManager manager =  null;
        Class<?>[] clazzs =  null;
        Object[] objs =  null;
        
        clazzs =  new Class<?>[1];
        clazzs[0] = OnActivityStopListener. class;
        
        objs =  new Object[1];
        objs[0] =  this;
        
        manager =  this.getPreferenceManager();
         try {
            method = PreferenceManager. class.getDeclaredMethod(name, clazzs);
            method.invoke(manager, objs);
        }  catch (Exception ex) {
        }
    }
    
    @Override
     protected  void onBindDialogView(View view) {
         super.onBindDialogView(view);       
         final SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
        mSeekBarVolumizer =  new SeekBarVolumizer(getContext(), seekBar, mStreamType);

        callActivityStopListener("registerOnActivityStopListener");

         //  grab focus and key events so that pressing the volume buttons in the
        
//  dialog doesn't also show the normal volume adjust toast.
        view.setOnKeyListener( this);
        view.setFocusableInTouchMode( true);
        view.requestFocus();
    }

    @Override
     public  boolean onKey(View v,  int keyCode, KeyEvent event) {
         if (mSeekBarVolumizer ==  nullreturn  true;
         boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_DOWN:
                 if (isdown) {
                    mSeekBarVolumizer.changeVolumeBy(-1);
                }
                 return  true;
             case KeyEvent.KEYCODE_VOLUME_UP:
                 if (isdown) {
                    mSeekBarVolumizer.changeVolumeBy(1);
                }
                 return  true;
             default:
                 return  false;
        }
    }
    
    @Override
     protected  void onDialogClosed( boolean positiveResult) {
         super.onDialogClosed(positiveResult);
        
         if (!positiveResult && mSeekBarVolumizer !=  null) {
            mSeekBarVolumizer.revertVolume();
        }

        cleanup();
    }

    @Override
     public  void onActivityStop() {
        cleanup();
    }

     private  void cleanup() {
        callActivityStopListener("unregisterOnActivityStopListener");

            if (mSeekBarVolumizer !=  null) {
               Dialog dialog = getDialog();
                if (dialog !=  null && dialog.isShowing()) {
                   View view = dialog.getWindow().getDecorView()
                           .findViewById(R.id.seekbar);
                    if (view !=  null) view.setOnKeyListener( null);
                    //  Stopped while dialog was showing, revert changes
                   mSeekBarVolumizer.revertVolume();
               }
               mSeekBarVolumizer.stop();
               mSeekBarVolumizer =  null;
           }

        }

         protected  void onSampleStarting(SeekBarVolumizer volumizer) {
             if (mSeekBarVolumizer !=  null && volumizer != mSeekBarVolumizer) {
                mSeekBarVolumizer.stopSample();
            }
        }

        @Override
         protected Parcelable onSaveInstanceState() {
             final Parcelable superState =  super.onSaveInstanceState();
             if (isPersistent()) {
                 //  No need to save instance state since it's persistent
                 return superState;
            }

             final SavedState myState =  new SavedState(superState);
             if (mSeekBarVolumizer !=  null) {
                mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
            }
             return myState;
        }

        @Override
         protected  void onRestoreInstanceState(Parcelable state) {
             if (state ==  null || !state.getClass().equals(SavedState. class)) {
                 //  Didn't save state for us in onSaveInstanceState
                 super.onRestoreInstanceState(state);
                 return;
            }

            SavedState myState = (SavedState) state;
             super.onRestoreInstanceState(myState.getSuperState());
             if (mSeekBarVolumizer !=  null) {
                mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
            }
        }

         public  static  class VolumeStore {
             public  int volume = -1;
             public  int originalVolume = -1;
        }

         private  static  class SavedState  extends BaseSavedState {
            VolumeStore mVolumeStore =  new VolumeStore();

             public SavedState(Parcel source) {
                 super(source);
                mVolumeStore.volume = source.readInt();
                mVolumeStore.originalVolume = source.readInt();
            }

            @Override
             public  void writeToParcel(Parcel dest,  int flags) {
                 super.writeToParcel(dest, flags);
                dest.writeInt(mVolumeStore.volume);
                dest.writeInt(mVolumeStore.originalVolume);
            }

            VolumeStore getVolumeStore() {
                 return mVolumeStore;
            }

             public SavedState(Parcelable superState) {
                 super(superState);
            }

             public  static  final Parcelable.Creator<SavedState> CREATOR =
                     new Parcelable.Creator<SavedState>() {
                 public SavedState createFromParcel(Parcel in) {
                     return  new SavedState(in);
                }

                 public SavedState[] newArray( int size) {
                     return  new SavedState[size];
                }
            };
        }

         /**
         * Turns a {
@link  SeekBar} into a volume control.
         
*/
         public  class SeekBarVolumizer  implements OnSeekBarChangeListener, Runnable {

             private Context mContext;
             private Handler mHandler =  new Handler();
        
             private AudioManager mAudioManager;
             private  int mStreamType;
             private  int mOriginalStreamVolume; 
             private Ringtone mRingtone;
        
             private  int mLastProgress = -1;
             private SeekBar mSeekBar;
            
             private ContentObserver mVolumeObserver =  new ContentObserver(mHandler) {
                @Override
                 public  void onChange( boolean selfChange) {
                     super.onChange(selfChange);
                     if (mSeekBar !=  null) {
                         int volume = System.getInt(mContext.getContentResolver(),
                                System.VOLUME_SETTINGS[mStreamType], -1);
                         //  Works around an atomicity problem with volume updates
                        
//  TODO: Fix the actual issue, probably in AudioService
                         if (volume >= 0) {
                            mSeekBar.setProgress(volume);
                        }
                    }
                }
            };

             public SeekBarVolumizer(Context context, SeekBar seekBar,  int streamType) {
                mContext = context;
                mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
                mStreamType = streamType;
                mSeekBar = seekBar;
                
                initSeekBar(seekBar);
            }

             private  void initSeekBar(SeekBar seekBar) {
                seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
                mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
                seekBar.setProgress(mOriginalStreamVolume);
                seekBar.setOnSeekBarChangeListener( this);
                
                mContext.getContentResolver().registerContentObserver(
                        System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
                         false, mVolumeObserver);
        
                Uri defaultUri =  null;
                 if (mStreamType == AudioManager.STREAM_RING) {
                    defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
                }  else  if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
                    defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
                }  else {
                    defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
                }

                mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
                 if (mRingtone !=  null) {
                    mRingtone.setStreamType(mStreamType);
                }
            }
            
             public  void stop() {
                stopSample();
                mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
                mSeekBar.setOnSeekBarChangeListener( null);
            }
            
             public  void revertVolume() {
                mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
            }
            
             public  void onProgressChanged(SeekBar seekBar,  int progress,
                     boolean fromTouch) {
                 if (!fromTouch) {
                     return;
                }
        
                postSetVolume(progress);
            }

             void postSetVolume( int progress) {
                 //  Do the volume changing separately to give responsive UI
                mLastProgress = progress;
                mHandler.removeCallbacks( this);
                mHandler.post( this);
            }
        
             public  void onStartTrackingTouch(SeekBar seekBar) {
            }

             public  void onStopTrackingTouch(SeekBar seekBar) {
                 if (mRingtone !=  null && !mRingtone.isPlaying()) {
                    sample();
                }
            }
            
             public  void run() {
                mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
            }
            
             private  void sample() {
                onSampleStarting( this);
                mRingtone.play();
            }
        
             public  void stopSample() {
                 if (mRingtone !=  null) {
                    mRingtone.stop();
                }
            }

             public SeekBar getSeekBar() {
                 return mSeekBar;
            }
            
             public  void changeVolumeBy( int amount) {
                mSeekBar.incrementProgressBy(amount);
                 if (mRingtone !=  null && !mRingtone.isPlaying()) {
                    sample();
                }
                postSetVolume(mSeekBar.getProgress());
            }

             public  void onSaveInstanceState(VolumeStore volumeStore) {
                 if (mLastProgress >= 0) {
                    volumeStore.volume = mLastProgress;
                    volumeStore.originalVolume = mOriginalStreamVolume;
                }
            }

             public  void onRestoreInstanceState(VolumeStore volumeStore) {
                 if (volumeStore.volume != -1) {
                    mOriginalStreamVolume = volumeStore.originalVolume;
                    mLastProgress = volumeStore.volume;
                    postSetVolume(mLastProgress);
                }
            }
        }

 

 

 

但是真个类还引用了另一个隐藏的类 SeekBarPreference 因此,还需要将这个类也导入到项目中

 

ExpandedBlockStart.gif View Code 
package apollo.preference;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import apollo.profilesetting.view.R;

public  class SeekBarPreferenceEx  extends DialogPreference {
     private Drawable mMyIcon;

     public SeekBarPreferenceEx(Context context, AttributeSet attrs) {
         super(context, attrs);

        setDialogLayoutResource(R.layout.seekbar_dialog);
        setPositiveButtonText(android.R.string.ok);
        setNegativeButtonText(android.R.string.cancel);
        
         //  Steal the XML dialogIcon attribute's value
        mMyIcon = getDialogIcon();
        setDialogIcon( null);
    }

    @Override
     protected  void onBindDialogView(View view) {
         super.onBindDialogView(view);
        
         final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
         if (mMyIcon !=  null) {
            iconView.setImageDrawable(mMyIcon);
        }  else {
            iconView.setVisibility(View.GONE);
        }
    }

     protected  static SeekBar getSeekBar(View dialogView) {
         return (SeekBar) dialogView.findViewById(R.id.seekbar);
    }

 

 

ok,酱紫我们就完成了对隐藏类的使用拉。不过在完成这个类的过程还需要使用反射的方法使用一些隐藏的类。

 

比如android.R.styleable,这个没有源代码可以使用,所以只能靠反射了。

 

原来的代码段:

 

 

         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VolumePreference, 0, 0);
         mStreamType = a.getInt(R.styleable.VolumePreference_streamType, 0);
         a.recycle();

 

 

用反射的办法实现该代码段

 

 

ExpandedBlockStart.gif View Code 
Class<?> clazz =  null;
         int[] styleable =  null;
        Field field =  null;
         int stream_type = 0;
        
         try {
            clazz = Class.forName("android.R$styleable");
            field = clazz.getField("VolumePreference");  
            styleable = ( int[])field.get(clazz);
            
            field = clazz.getField("VolumePreference");  
            stream_type = (Integer)field.get(clazz);
        }  catch (Exception ex) {
        }

        
        
        TypedArray a = context.obtainStyledAttributes(attrs, styleable, 0, 0);
        mStreamType = a.getInt(stream_type, 0);

 

还有其他的代码是需要反射实现的,看VolumePreference.callActivityStopListener方法就知道拉  ok,这样,我们就完成这个隐藏类的“实现”拉。 

 

 

 

转载于:https://www.cnblogs.com/wii/archive/2012/03/28/VolumePreference.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值