content: /*
       This file is part of Subsonic.
  
       Subsonic is free software: you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation, either version 3 of the License, or
       (at your option) any later version.
  
       Subsonic is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.
  
       You should have received a copy of the GNU General Public License
       along with Subsonic.  If not, see <http://www.gnu.org/licenses/>.
  
       Copyright 2014 (C) Scott Jackson
  */
  
  package net.nullsum.audinaut.fragments;
  
  import android.app.Activity;
  import android.content.Context;
  import android.content.Intent;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.preference.Preference;
  import android.preference.PreferenceManager;
  import android.preference.PreferenceScreen;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.ListView;
  
  import net.nullsum.audinaut.R;
  import net.nullsum.audinaut.util.Constants;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  
  public abstract class PreferenceCompatFragment extends SubsonicFragment {
      private static final int FIRST_REQUEST_CODE = 100;
      private static final int MSG_BIND_PREFERENCES = 1;
      private static final String PREFERENCES_TAG = "android:preferences";
      private boolean mHavePrefs;
      private boolean mInitDone;
      private ListView mList;
      final private Runnable mRequestFocus = new Runnable() {
          public void run() {
              mList.focusableViewAvailable(mList);
          }
      };
      private PreferenceManager mPreferenceManager;
      private final Handler mHandler = new Handler() {
          @Override
          public void handleMessage(Message msg) {
              switch (msg.what) {
  
                  case MSG_BIND_PREFERENCES:
                      bindPreferences();
                      break;
              }
          }
      };
  
      private void bindPreferences() {
          PreferenceScreen localPreferenceScreen = getPreferenceScreen();
          if (localPreferenceScreen != null) {
              ListView localListView = getListView();
              localPreferenceScreen.bind(localListView);
          }
      }
  
      private void ensureList() {
          if (mList == null) {
              View view = getView();
              if (view == null) {
                  throw new IllegalStateException("Content view not yet created");
              }
  
              View listView = view.findViewById(android.R.id.list);
              if (!(listView instanceof ListView)) {
                  throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class");
              }
  
              mList = (ListView) listView;
  
              mHandler.post(mRequestFocus);
          }
      }
  
      private void postBindPreferences() {
          if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) {
              mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
          }
      }
  
      private void requirePreferenceManager() {
          if (this.mPreferenceManager == null) {
              throw new RuntimeException("This should be called after super.onCreate.");
          }
      }
  
      private PreferenceScreen addPreferencesFromResource(int resId) {
          requirePreferenceManager();
          PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen());
          setPreferenceScreen(screen);
  
          for (int i = 0; i < screen.getPreferenceCount(); i++) {
              Preference preference = screen.getPreference(i);
              if (preference instanceof PreferenceScreen && preference.getKey() != null) {
                  preference.setOnPreferenceClickListener(preference1 -> {
                      onStartNewFragment(preference1.getKey());
                      return false;
                  });
              }
          }
  
          return screen;
      }
  
      Preference findPreference(CharSequence key) {
          if (mPreferenceManager == null) {
              return null;
          }
          return mPreferenceManager.findPreference(key);
      }
  
      private ListView getListView() {
          ensureList();
          return mList;
      }
  
      PreferenceManager getPreferenceManager() {
          return mPreferenceManager;
      }
  
      @Override
      public void onActivityCreated(Bundle savedInstanceState) {
          super.onActivityCreated(savedInstanceState);
          getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
          if (mHavePrefs) {
              bindPreferences();
          }
          mInitDone = true;
          if (savedInstanceState != null) {
              Bundle localBundle = savedInstanceState.getBundle(PREFERENCES_TAG);
              if (localBundle != null) {
                  PreferenceScreen screen = getPreferenceScreen();
                  if (screen != null) {
                      screen.restoreHierarchyState(localBundle);
                  }
              }
          }
      }
  
      @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data) {
          super.onActivityResult(requestCode, resultCode, data);
          dispatchActivityResult(requestCode, resultCode, data);
      }
  
      @Override
      public void onCreate(Bundle paramBundle) {
          super.onCreate(paramBundle);
          mPreferenceManager = createPreferenceManager();
  
          int res = this.getArguments().getInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, 0);
          if (res != 0) {
              PreferenceScreen preferenceScreen = addPreferencesFromResource(res);
              onInitPreferences(preferenceScreen);
          }
      }
  
      @Override
      public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
          return paramLayoutInflater.inflate(R.layout.preferences, paramViewGroup, false);
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          dispatchActivityDestroy();
      }
  
      @Override
      public void onDestroyView() {
          mList = null;
          mHandler.removeCallbacks(mRequestFocus);
          mHandler.removeMessages(MSG_BIND_PREFERENCES);
          super.onDestroyView();
      }
  
      @Override
      public void onSaveInstanceState(Bundle bundle) {
          super.onSaveInstanceState(bundle);
          PreferenceScreen screen = getPreferenceScreen();
          if (screen != null) {
              Bundle localBundle = new Bundle();
              screen.saveHierarchyState(localBundle);
              bundle.putBundle(PREFERENCES_TAG, localBundle);
          }
      }
  
      @Override
      public void onStop() {
          super.onStop();
          dispatchActivityStop();
      }
  
      /**
       * Access methods with visibility private
       **/
  
      private PreferenceManager createPreferenceManager() {
          try {
              Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
              c.setAccessible(true);
              return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private PreferenceScreen getPreferenceScreen() {
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
              m.setAccessible(true);
              return (PreferenceScreen) m.invoke(mPreferenceManager);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      void setPreferenceScreen(PreferenceScreen preferenceScreen) {
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
              m.setAccessible(true);
              boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen);
              if (result && preferenceScreen != null) {
                  mHavePrefs = true;
                  if (mInitDone) {
                      postBindPreferences();
                  }
              }
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
              m.setAccessible(true);
              m.invoke(mPreferenceManager, requestCode, resultCode, data);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private void dispatchActivityDestroy() {
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
              m.setAccessible(true);
              m.invoke(mPreferenceManager);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private void dispatchActivityStop() {
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
              m.setAccessible(true);
              m.invoke(mPreferenceManager);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      private PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) {
          PreferenceScreen preferenceScreen;
          try {
              Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
              m.setAccessible(true);
              preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, context, resId, rootPreferences);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          return preferenceScreen;
      }
  
      protected abstract void onInitPreferences(PreferenceScreen preferenceScreen);
  
      protected abstract void onStartNewFragment(String name);
  }
  