Recently in the customization of the Android system volume bar, found that the code is quite a bit, summarized below.
The code is based on the 5.1.1 version.
The code for the system volume bar is in/frameworks/base/packages/systemui/src/com/android/systemui/volume/volumepanel.java
The layout file is under/frameworks/base/packages/systemui/res/layout.
First look at the native volume bar style:
In the code can find volume_dialog.xml this file, this file is the layout of the bearer volume bar, in the Layout folder found open will find this layout is simple, just include a volume_panel.
The Volume_panel layout contains an ID called Slider_panel framelayout and includes a zen_mode_panel, and obviously Slider_panel is later included Seekbar, See Volumepanel.java also found in the code loaded volume_panel_item.xml this file, a look, found inside contains seekbar this control. Another zen_mode_panel refers to the Do Not Disturb mode.
When you look at this layout file, you will see the Android:clipchildren property, which is the function of whether to restrict the sub-view within its scope, we set its value to false then when the child control height is higher than the parent control will also be fully displayed, and will not be compressed. The default is true.
If you want a control to not display, set the property android:visibility= "Gone" is good.
After reading the layout, the following is the main look volumepanel.java this file.
The
Volumepanel defines two important subtypes, namely streamresources and Streamcontrol. Streamresources is actually an enumeration, and each of its available elements holds the various resources required for a stream-type notification box, such as icons, hint text, and so on. The definition of streamresources is as follows:
Private enum Streamresources {bluetoothscostream (Audiomanager.stream_bluetooth_sco, r.string.
Volume_icon_description_bluetooth, IC_AUDIO_BT, Ic_audio_bt_mute, false), This omits the construction parameters of several of the following enumerated items, which are consistent with the contents of the Bluetoothscostream ringerstream (...), VoiceStream (...), Al Armstream (...), MediaStream (...), Notificationstream (...),//For now, use media resources for MAS ter volume Masterstream (...), Remotestream (...); /'ll be dynamically updated int streamtype; Flow type int descres; Description information int iconres; icon int iconmuteres; Mute icon//RING, Voice_call & Bluetooth_sco is hidden unless explicitly requested Boolean show;
Whether to display//constructor streamresources (int streamtype, int descres, int iconres, int iconmuteres, Boolean show) {
...
} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
These enumeration items make up an array named stream, as follows:
private static final streamresources[] STREAMS = {
Streamresources.bluetoothscostream,
Streamresources.ringerstream,
Streamresources.voicestream,
Streamresources.mediastream,
Streamresources.notificationstream,
Streamresources.alarmstream,
Streamresources.masterstream,
Streamresources.remotestream
};
1 2 3 4 5 6 7 8 9 10
Volumepanel will get the associated resources for the type of flow it supports from this streams array.
The Streamcontrol class holds the control that is required to display a notification box for a stream type, which is defined as follows:
/** Object, contains data for each slider */
Private class Streamcontrol {
int streamtype;
Mediacontroller Controller;
ViewGroup Group;
ImageView icon;
SeekBar Seekbarview;
TextView Suppressorview;
View Divider;
ImageView Secondaryicon;
int iconres;
int iconmuteres;
int iconsuppressedres;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14
All the controls required in the volume adjustment notification box are saved in the Streamcontrol instance. For operational efficiency considerations, the Streamcontrol instance is also a manual for each flow type, and the Streamresources instance forms a one by one corresponding relationship. All Streamcontrol instances are stored in a sparsearray with the value of the stream type, named Mstreamcontrols. Can be seen in the Streamcontrol initialization function createsliders ().
private void Createsliders () {
...
Traverse all streamresources instances in the stream for
(int i = 0; i < streams.length; i++) {
streamresources streamres = STREAMS [i];
Final int streamtype = Streamres.streamtype;
...
Final Streamcontrol sc = new Streamcontrol ();//Create a Streamcontrol//for Streamtype to
initialize the member variable of SC
...
Sc.seekbarView.setOnSeekBarChangeListener (Mseeklistener); Set the monitoring
mstreamcontrols.put (Streamtype, SC);//Put the initialized sc into the Mstreamcontrols
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Private final Onseekbarchangelistener Mseeklistener = new Onseekbarchangelistener () {
@Override public
Void Onprogresschanged (SeekBar SeekBar, int progress, Boolean Fromuser) {
final Object tag = Seekbar.gettag ();
if (fromuser && tag instanceof streamcontrol) {
Streamcontrol sc = (streamcontrol) tag;
Set Volume
Setstreamvolume (SC, PROGRESS,AUDIOMANAGER.FLAG_SHOW_UI | audiomanager.flag_vibrate);
}
Resettimeout ();
}
...
};
1 2 3 4 5 6 7 8 9 10 11 12 13
This initialization work is not performed in the constructor, but is handled in the postvolumechanged (), postremotevolumechanged (), postmutechanged () functions.
Volumepanel saved a dialog instance named Mdialog, which is the notification box itself. Whenever a new volume change arrives, the contents of the Mdialog are replaced with the controls saved in the Streamcontrol for the specified stream type, and the position of the volume bar is set according to the volume change, and the last Call to Mdialog.show () is displayed. At the same time, send a delay message msg_timeout, this delay message takes effect, will close the prompt box.
The next step is to see what Volumepanel has done after receiving the volume change notification.
Instead of calling directly in the postvolumechanged () function, Volumepanel calls the onvolumechanged () function in the Msg_volume_changed message handler function. It makes sense to do so. Because Android requires that the control be manipulated only in the thread that created the control. Postvolumechanged () is a callback-nature function that does not require the caller to be in which thread. Therefore, the subsequent operations must be transferred to the specified thread by sending a message to the handler.
Let's take a look at the implementation of the Onvolumechanged () function:
protected void onvolumechanged (int streamtype, int flags) {//need to include AUDIOMANAGER.FLAG_SHOW_UI in flags to display volume adjustment Section notification box if ((Flags & audiomanager.flag_show_ui)! = 0) {synchronized (this) {if (mAc
Tivestreamtype! = Streamtype) {reordersliders (streamtype);//load Required dialog in Streamcontrol
} onshowvolumechanged (Streamtype, flags, NULL); }}//whether to broadcast tone tone, note there is a small delay if ((Flags & audiomanager.flag_play_sound)! = 0 &&! mringiss
Ilent) {removemessages (msg_play_sound);
Sendmessagedelayed (Obtainmessage (Msg_play_sound, Streamtype, Flags), play_sound_delay); }//Cancel sound and vibrate play if ((Flags & audiomanager.flag_remove_sound_and_vibrate)! = 0) {Removemes
Sages (msg_play_sound);
Removemessages (msg_vibrate);
Onstopsounds (); }//start to Schedule recycling resources removemessages (Msg_Free_resources);
Sendmessagedelayed (Obtainmessage (msg_free_resources), free_delay); Resettimeout (); Reset Volume box timeout time to close}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Note the last Resettimeout () call, in fact it re-delays sending the msg_timeout message. When the msg_timeout message is in effect, Mdialog will be closed.
After that, onshowvolumechanged (). This function is responsible for filling the contents of the Notification box with the volume, chart, and so on, and then displaying the notification box (if it is not yet displayed).
protected void onshowvolumechanged (int streamtype, int flags, Mediacontroller Controller) {int index = GETSTR Eamvolume (Streamtype);//Get the volume value int max = Getstreammaxvolume (Streamtype);
Get the maximum volume, both of which will be used to set the progress bar Streamcontrol sc = mstreamcontrols.get (streamtype); In this switch statement, we will make various adjustments based on the characteristics of each stream type. For example, music sometimes needs to update its icon, because the use of Bluetooth headset when the icon is not the same as usual, so every time you need to update switch (streamtype) {case Audiomanager.stream_mus IC: {///special case for when Bluetooth was active for music if (maudiomanager.getdevices
Forstream (Audiomanager.stream_music) & (AUDIOMANAGER.DEVICE_OUT_BLUETOOTH_A2DP |
Audiomanager.device_out_bluetooth_a2dp_headphones |
Audiomanager.device_out_bluetooth_a2dp_speaker))! = 0) {Setmusicicon (IC_AUDIO_BT, Ic_audio_bt_mute);
} else {Setmusicicon (Ic_audio_vol, Ic_audio_vol_mute); } break;
}
...
} if (sc! = null) {... updatesliderprogress (SC, index);//update Seekbar display final Boolean m
uted = ismuted (Streamtype);
Updatesliderenabled (SC, muted, (Flags & audiomanager.flag_fixed_volume)! = 0); ... Updateslidericon (SC, muted); Update Stream_icon}} if (!isshowing ()) {//If the dialog box does not yet show int stream = (Streamtype = = Stream_remote_music)?
-1:streamtype; Once this notification box is displayed, pressing the volume key only adjusts the volume of the current stream type. Call Forcevolumecontrolstream () again until the notification box is closed, and set Streamtype to 1 if (stream! = stream_master) {Maudio
Manager.forcevolumecontrolstream (stream); } mdialog.show ();
Show dialog box ...} Do a little vibrate if applicable (only if going into vibrate mode) if ((Streamtype! = stream_remote_music) &
amp;&((Flags & audiomanager.flag_vibrate)! = 0) && isnotificationorring (streamtype) && Maudiomanager.getringermodeinternal () = = Audiomanager.ringer_mode_vibrate) {sendmessagedelayed (ob Tainmessage (msg_vibrate), Vibrate_delay)///slightly vibrating (only when entering vibration mode)} ...}